]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.api.acr/src/org/argeo/api/acr/NamespaceUtils.java
Introduce UUID identified and openForEdit/freeze cycle
[lgpl/argeo-commons.git] / org.argeo.api.acr / src / org / argeo / api / acr / NamespaceUtils.java
1 package org.argeo.api.acr;
2
3 import java.util.Collections;
4 import java.util.Comparator;
5 import java.util.Iterator;
6 import java.util.Objects;
7 import java.util.Set;
8 import java.util.function.Function;
9
10 import javax.xml.XMLConstants;
11 import javax.xml.namespace.NamespaceContext;
12 import javax.xml.namespace.QName;
13
14 /** Static utilities around namespaces and prefixes. */
15 public class NamespaceUtils {
16 /**
17 * A {@link Comparator} ordering by namespace (full URI) and then local part.
18 */
19 public final static Comparator<QName> QNAME_COMPARATOR = new Comparator<QName>() {
20
21 @Override
22 public int compare(QName qn1, QName qn2) {
23 if (Objects.equals(qn1.getNamespaceURI(), qn2.getNamespaceURI())) {// same namespace
24 return qn1.getLocalPart().compareTo(qn2.getLocalPart());
25 } else {
26 return qn1.getNamespaceURI().compareTo(qn2.getNamespaceURI());
27 }
28 }
29
30 };
31
32 /**
33 * Return a {@link ContentName} from a prefixed name, using the default runtime
34 * {@link NamespaceContext}.
35 *
36 * @see RuntimeNamespaceContext#getNamespaceContext()
37 */
38 public static ContentName parsePrefixedName(String nameWithPrefix) {
39 return parsePrefixedName(RuntimeNamespaceContext.getNamespaceContext(), nameWithPrefix);
40 }
41
42 /**
43 * Return a {@link ContentName} from a prefixed name, using the provided
44 * {@link NamespaceContext}. Since {@link QName#QName(String, String)} does not
45 * validate, it can conceptually parse a CURIE.
46 *
47 * @see https://en.wikipedia.org/wiki/CURIE
48 */
49 public static ContentName parsePrefixedName(NamespaceContext nameSpaceContext, String nameWithPrefix) {
50 Objects.requireNonNull(nameWithPrefix, "Name cannot be null");
51 if (nameWithPrefix.charAt(0) == '{') {
52 return new ContentName(QName.valueOf(nameWithPrefix), nameSpaceContext);
53 }
54 int index = nameWithPrefix.indexOf(':');
55 if (index < 0) {
56 return new ContentName(nameWithPrefix);
57 }
58 String prefix = nameWithPrefix.substring(0, index);
59 // TODO deal with empty name?
60 String localName = nameWithPrefix.substring(index + 1);
61 String namespaceURI = nameSpaceContext.getNamespaceURI(prefix);
62 if (XMLConstants.NULL_NS_URI.equals(namespaceURI))
63 throw new IllegalArgumentException("Prefix " + prefix + " is unbound.");
64 return new ContentName(namespaceURI, localName, prefix);
65 }
66
67 /**
68 * The prefixed name of this {@link QName}, using the default runtime
69 * {@link NamespaceContext}.
70 *
71 * @see RuntimeNamespaceContext#getNamespaceContext()
72 */
73 public static String toPrefixedName(QName name) {
74 return toPrefixedName(RuntimeNamespaceContext.getNamespaceContext(), name);
75 }
76
77 /**
78 * The prefixed name of this {@link QName}, using the provided
79 * {@link NamespaceContext}.
80 */
81 public static String toPrefixedName(NamespaceContext nameSpaceContext, QName name) {
82 if (XMLConstants.NULL_NS_URI.equals(name.getNamespaceURI()))
83 return name.getLocalPart();
84 String prefix = nameSpaceContext.getPrefix(name.getNamespaceURI());
85 if (prefix == null)
86 throw new IllegalStateException("Namespace " + name.getNamespaceURI() + " is unbound.");
87 return prefix + ":" + name.getLocalPart();
88 }
89
90 /**
91 * Whether thei {@link QName} has a namespace, that is its namespace is not
92 * {@link XMLConstants#NULL_NS_URI}.
93 */
94 public static boolean hasNamespace(QName qName) {
95 return !qName.getNamespaceURI().equals(XMLConstants.NULL_NS_URI);
96 }
97
98 /** Throws an exception if the provided string has a prefix. */
99 public static void checkNoPrefix(String unqualified) throws IllegalArgumentException {
100 if (unqualified.indexOf(':') >= 0)
101 throw new IllegalArgumentException("Name " + unqualified + " has a prefix");
102 }
103
104 /**
105 * Create an unqualified {@link QName}, checking that the argument does not
106 * contain a prefix.
107 */
108 public static QName unqualified(String name) {
109 checkNoPrefix(name);
110 return new ContentName(XMLConstants.NULL_NS_URI, name, XMLConstants.DEFAULT_NS_PREFIX);
111
112 }
113
114 /**
115 * The common (fully qualified) representation of this name, as defined in
116 * {@link QName#toString()}. This should be used when a fully qualified
117 * representation is required, as subclasses of {@link QName} may override the
118 * {@link QName#toString()} method.
119 *
120 * @see ContentName#toString()
121 */
122 public static String toFullyQualified(QName name) {
123 if (name.getNamespaceURI().equals(XMLConstants.NULL_NS_URI)) {
124 return name.getLocalPart();
125 } else {
126 return "{" + name.getNamespaceURI() + "}" + name.getLocalPart();
127 }
128
129 }
130
131 /*
132 * STANDARD NAMESPACE CONTEXT OPERATIONS as specified in NamespaceContext
133 */
134 /**
135 * The standard prefix for well known namespaces as defined in
136 * {@link NamespaceContext}, or null if the namespace is not well-known. Helper
137 * method simplifying the implementation of a {@link NamespaceContext}.
138 *
139 * @see NamespaceContext#getPrefix(String)
140 */
141 public static String getStandardPrefix(String namespaceURI) {
142 if (namespaceURI == null)
143 throw new IllegalArgumentException("Namespace URI cannot be null");
144 if (XMLConstants.XML_NS_URI.equals(namespaceURI))
145 return XMLConstants.XML_NS_PREFIX;
146 else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI))
147 return XMLConstants.XMLNS_ATTRIBUTE;
148 return null;
149 }
150
151 /**
152 * The standard prefixes for well known namespaces as defined in
153 * {@link NamespaceContext}, or null if the namespace is not well-known. Helper
154 * method simplifying the implementation of a {@link NamespaceContext}.
155 *
156 * @see NamespaceContext#getPrefixes(String)
157 */
158 public static Iterator<String> getStandardPrefixes(String namespaceURI) {
159 String prefix = getStandardPrefix(namespaceURI);
160 if (prefix == null)
161 return null;
162 return Collections.singleton(prefix).iterator();
163 }
164
165 /**
166 * The standard URI for well known prefixes as defined in
167 * {@link NamespaceContext}, or null if the prefix is not well-known. Helper
168 * method simplifying the implementation of a {@link NamespaceContext}.
169 *
170 * @see NamespaceContext#getNamespaceURI(String)
171 */
172 public static String getStandardNamespaceURI(String prefix) {
173 if (prefix == null)
174 throw new IllegalArgumentException("Prefix cannot be null");
175 if (XMLConstants.XML_NS_PREFIX.equals(prefix))
176 return XMLConstants.XML_NS_URI;
177 else if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix))
178 return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
179 return null;
180 }
181
182 /**
183 * The namespace URI for a given prefix, based on the provided mapping and the
184 * standard prefixes/URIs.
185 *
186 * @return the namespace URI for this prefix, or
187 * {@link XMLConstants#NULL_NS_URI} if unknown.
188 */
189 public static String getNamespaceURI(Function<String, String> mapping, String prefix) {
190 String namespaceURI = NamespaceUtils.getStandardNamespaceURI(prefix);
191 if (namespaceURI != null)
192 return namespaceURI;
193 if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix))
194 return XMLConstants.NULL_NS_URI;
195 namespaceURI = mapping.apply(prefix);
196 if (namespaceURI != null)
197 return namespaceURI;
198 return XMLConstants.NULL_NS_URI;
199 }
200
201 /**
202 * The prefix for a given namespace URI, based on the provided mapping and the
203 * standard prefixes/URIs.
204 *
205 * @return the prefix for this namespace URI. What is returned or throws as
206 * exception if the prefix is not found depdnds on the mapping function.
207 */
208 public static String getPrefix(Function<String, String> mapping, String namespaceURI) {
209 String prefix = NamespaceUtils.getStandardPrefix(namespaceURI);
210 if (prefix != null)
211 return prefix;
212 if (XMLConstants.NULL_NS_URI.equals(namespaceURI))
213 return XMLConstants.DEFAULT_NS_PREFIX;
214 return mapping.apply(namespaceURI);
215 }
216
217 /**
218 * The prefixes for a given namespace URI, based on the provided mapping and the
219 * standard prefixes/URIs.
220 *
221 * @return the prefixes for this namespace URI. What is returned or throws as
222 * exception if the prefix is not found depdnds on the mapping function.
223 */
224 public static Iterator<String> getPrefixes(Function<String, Set<String>> mapping, String namespaceURI) {
225 Iterator<String> standard = NamespaceUtils.getStandardPrefixes(namespaceURI);
226 if (standard != null)
227 return standard;
228 if (XMLConstants.NULL_NS_URI.equals(namespaceURI))
229 return Collections.singleton(XMLConstants.DEFAULT_NS_PREFIX).iterator();
230 Set<String> prefixes = mapping.apply(namespaceURI);
231 assert prefixes != null;
232 return prefixes.iterator();
233 }
234
235 /** singleton */
236 private NamespaceUtils() {
237 }
238
239 }