1 package org
.argeo
.api
.acr
;
3 import java
.util
.Collections
;
4 import java
.util
.Comparator
;
5 import java
.util
.Iterator
;
6 import java
.util
.Objects
;
8 import java
.util
.function
.Function
;
10 import javax
.xml
.XMLConstants
;
11 import javax
.xml
.namespace
.NamespaceContext
;
12 import javax
.xml
.namespace
.QName
;
14 /** Static utilities around namespaces and prefixes. */
15 public class NamespaceUtils
{
17 * A {@link Comparator} ordering by namespace (full URI) and then local part.
19 public final static Comparator
<QName
> QNAME_COMPARATOR
= new Comparator
<QName
>() {
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());
26 return qn1
.getNamespaceURI().compareTo(qn2
.getNamespaceURI());
33 * Return a {@link ContentName} from a prefixed name, using the default runtime
34 * {@link NamespaceContext}.
36 * @see RuntimeNamespaceContext#getNamespaceContext()
38 public static ContentName
parsePrefixedName(String nameWithPrefix
) {
39 return parsePrefixedName(RuntimeNamespaceContext
.getNamespaceContext(), nameWithPrefix
);
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.
47 * @see https://en.wikipedia.org/wiki/CURIE
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
);
54 int index
= nameWithPrefix
.indexOf(':');
56 return new ContentName(nameWithPrefix
);
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
);
68 * The prefixed name of this {@link QName}, using the default runtime
69 * {@link NamespaceContext}.
71 * @see RuntimeNamespaceContext#getNamespaceContext()
73 public static String
toPrefixedName(QName name
) {
74 return toPrefixedName(RuntimeNamespaceContext
.getNamespaceContext(), name
);
78 * The prefixed name of this {@link QName}, using the provided
79 * {@link NamespaceContext}.
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());
86 throw new IllegalStateException("Namespace " + name
.getNamespaceURI() + " is unbound.");
87 return prefix
+ ":" + name
.getLocalPart();
91 * Whether thei {@link QName} has a namespace, that is its namespace is not
92 * {@link XMLConstants#NULL_NS_URI}.
94 public static boolean hasNamespace(QName qName
) {
95 return !qName
.getNamespaceURI().equals(XMLConstants
.NULL_NS_URI
);
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");
105 * Create an unqualified {@link QName}, checking that the argument does not
108 public static QName
unqualified(String name
) {
110 return new ContentName(XMLConstants
.NULL_NS_URI
, name
, XMLConstants
.DEFAULT_NS_PREFIX
);
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.
120 * @see ContentName#toString()
122 public static String
toFullyQualified(QName name
) {
123 if (name
.getNamespaceURI().equals(XMLConstants
.NULL_NS_URI
)) {
124 return name
.getLocalPart();
126 return "{" + name
.getNamespaceURI() + "}" + name
.getLocalPart();
132 * STANDARD NAMESPACE CONTEXT OPERATIONS as specified in NamespaceContext
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}.
139 * @see NamespaceContext#getPrefix(String)
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
;
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}.
156 * @see NamespaceContext#getPrefixes(String)
158 public static Iterator
<String
> getStandardPrefixes(String namespaceURI
) {
159 String prefix
= getStandardPrefix(namespaceURI
);
162 return Collections
.singleton(prefix
).iterator();
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}.
170 * @see NamespaceContext#getNamespaceURI(String)
172 public static String
getStandardNamespaceURI(String prefix
) {
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
;
183 * The namespace URI for a given prefix, based on the provided mapping and the
184 * standard prefixes/URIs.
186 * @return the namespace URI for this prefix, or
187 * {@link XMLConstants#NULL_NS_URI} if unknown.
189 public static String
getNamespaceURI(Function
<String
, String
> mapping
, String prefix
) {
190 String namespaceURI
= NamespaceUtils
.getStandardNamespaceURI(prefix
);
191 if (namespaceURI
!= null)
193 if (XMLConstants
.DEFAULT_NS_PREFIX
.equals(prefix
))
194 return XMLConstants
.NULL_NS_URI
;
195 namespaceURI
= mapping
.apply(prefix
);
196 if (namespaceURI
!= null)
198 return XMLConstants
.NULL_NS_URI
;
202 * The prefix for a given namespace URI, based on the provided mapping and the
203 * standard prefixes/URIs.
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.
208 public static String
getPrefix(Function
<String
, String
> mapping
, String namespaceURI
) {
209 String prefix
= NamespaceUtils
.getStandardPrefix(namespaceURI
);
212 if (XMLConstants
.NULL_NS_URI
.equals(namespaceURI
))
213 return XMLConstants
.DEFAULT_NS_PREFIX
;
214 return mapping
.apply(namespaceURI
);
218 * The prefixes for a given namespace URI, based on the provided mapping and the
219 * standard prefixes/URIs.
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.
224 public static Iterator
<String
> getPrefixes(Function
<String
, Set
<String
>> mapping
, String namespaceURI
) {
225 Iterator
<String
> standard
= NamespaceUtils
.getStandardPrefixes(namespaceURI
);
226 if (standard
!= null)
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();
236 private NamespaceUtils() {