001/* 002Copyright (c) 2011+, HL7, Inc 003All rights reserved. 004 005Redistribution and use in source and binary forms, with or without modification, 006are permitted provided that the following conditions are met: 007 008 * Redistributions of source code must retain the above copyright notice, this 009 list of conditions and the following disclaimer. 010 * Redistributions in binary form must reproduce the above copyright notice, 011 this list of conditions and the following disclaimer in the documentation 012 and/or other materials provided with the distribution. 013 * Neither the name of HL7 nor the names of its contributors may be used to 014 endorse or promote products derived from this software without specific 015 prior written permission. 016 017THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 018ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 019WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 020IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 021INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 022NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 023PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 024WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 025ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 026POSSIBILITY OF SUCH DAMAGE. 027 028*/ 029package org.hl7.fhir.utilities.xml; 030 031// see http://illegalargumentexception.blogspot.com.au/2009/05/java-using-xpath-with-namespaces-and.html 032 033import java.util.Collections; 034import java.util.HashMap; 035import java.util.HashSet; 036import java.util.Iterator; 037import java.util.Map; 038import java.util.Set; 039 040import javax.xml.XMLConstants; 041import javax.xml.namespace.NamespaceContext; 042 043/** 044* An implementation of <a 045* href="http://java.sun.com/javase/6/docs/api/javax/xml/namespace/NamespaceContext.html"> 046* NamespaceContext </a>. Instances are immutable. 047* 048* @author McDowell 049*/ 050public final class NamespaceContextMap implements NamespaceContext { 051 052 private final Map<String, String> prefixMap; 053 private final Map<String, Set<String>> nsMap; 054 055 /** 056 * Constructor that takes a map of XML prefix-namespaceURI values. A defensive 057 * copy is made of the map. An IllegalArgumentException will be thrown if the 058 * map attempts to remap the standard prefixes defined in the NamespaceContext 059 * contract. 060 * 061 * @param prefixMappings 062 * a map of prefix:namespaceURI values 063 */ 064 public NamespaceContextMap( 065 Map<String, String> prefixMappings) { 066 prefixMap = createPrefixMap(prefixMappings); 067 nsMap = createNamespaceMap(prefixMap); 068 } 069 070 /** 071 * Convenience constructor. 072 * 073 * @param mappingPairs 074 * pairs of prefix-namespaceURI values 075 */ 076 public NamespaceContextMap(String... mappingPairs) { 077 this(toMap(mappingPairs)); 078 } 079 080 private static Map<String, String> toMap( 081 String... mappingPairs) { 082 Map<String, String> prefixMappings = new HashMap<String, String>( 083 mappingPairs.length / 2); 084 for (int i = 0; i < mappingPairs.length; i++) { 085 prefixMappings 086 .put(mappingPairs[i], mappingPairs[++i]); 087 } 088 return prefixMappings; 089 } 090 091 private Map<String, String> createPrefixMap( 092 Map<String, String> prefixMappings) { 093 Map<String, String> prefixMap = new HashMap<String, String>( 094 prefixMappings); 095 addConstant(prefixMap, XMLConstants.XML_NS_PREFIX, 096 XMLConstants.XML_NS_URI); 097 addConstant(prefixMap, XMLConstants.XMLNS_ATTRIBUTE, 098 XMLConstants.XMLNS_ATTRIBUTE_NS_URI); 099 return Collections.unmodifiableMap(prefixMap); 100 } 101 102 private void addConstant(Map<String, String> prefixMap, 103 String prefix, String nsURI) { 104 String previous = prefixMap.put(prefix, nsURI); 105 if (previous != null && !previous.equals(nsURI)) { 106 throw new IllegalArgumentException(prefix + " -> " 107 + previous + "; see NamespaceContext contract"); 108 } 109 } 110 111 private Map<String, Set<String>> createNamespaceMap( 112 Map<String, String> prefixMap) { 113 Map<String, Set<String>> nsMap = new HashMap<String, Set<String>>(); 114 for (Map.Entry<String, String> entry : prefixMap 115 .entrySet()) { 116 String nsURI = entry.getValue(); 117 Set<String> prefixes = nsMap.get(nsURI); 118 if (prefixes == null) { 119 prefixes = new HashSet<String>(); 120 nsMap.put(nsURI, prefixes); 121 } 122 prefixes.add(entry.getKey()); 123 } 124 for (Map.Entry<String, Set<String>> entry : nsMap 125 .entrySet()) { 126 Set<String> readOnly = Collections 127 .unmodifiableSet(entry.getValue()); 128 entry.setValue(readOnly); 129 } 130 return nsMap; 131 } 132 133 @Override 134 public String getNamespaceURI(String prefix) { 135 checkNotNull(prefix); 136 String nsURI = prefixMap.get(prefix); 137 return nsURI == null ? XMLConstants.NULL_NS_URI : nsURI; 138 } 139 140 @Override 141 public String getPrefix(String namespaceURI) { 142 checkNotNull(namespaceURI); 143 Set<String> set = nsMap.get(namespaceURI); 144 return set == null ? null : set.iterator().next(); 145 } 146 147 @Override 148 public Iterator<String> getPrefixes(String namespaceURI) { 149 checkNotNull(namespaceURI); 150 Set<String> set = nsMap.get(namespaceURI); 151 return set.iterator(); 152 } 153 154 private void checkNotNull(String value) { 155 if (value == null) { 156 throw new IllegalArgumentException("null"); 157 } 158 } 159 160 /** 161 * @return an unmodifiable map of the mappings in the form prefix-namespaceURI 162 */ 163 public Map<String, String> getMap() { 164 return prefixMap; 165 } 166 167}