You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
712 lines
19 KiB
712 lines
19 KiB
/*
|
|
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*/
|
|
/*
|
|
* Copyright 1999-2004 The Apache Software Foundation.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
/*
|
|
* $Id: QName.java,v 1.2.4.1 2005/09/15 08:15:52 suresh_emailid Exp $
|
|
*/
|
|
package com.sun.org.apache.xml.internal.utils;
|
|
|
|
import java.util.Stack;
|
|
import java.util.StringTokenizer;
|
|
|
|
import com.sun.org.apache.xml.internal.res.XMLErrorResources;
|
|
import com.sun.org.apache.xml.internal.res.XMLMessages;
|
|
|
|
import org.w3c.dom.Element;
|
|
|
|
/**
|
|
* Class to represent a qualified name: "The name of an internal XSLT object,
|
|
* specifically a named template (see [7 Named Templates]), a mode (see [6.7 Modes]),
|
|
* an attribute set (see [8.1.4 Named Attribute Sets]), a key (see [14.2 Keys]),
|
|
* a locale (see [14.3 Number Formatting]), a variable or a parameter (see
|
|
* [12 Variables and Parameters]) is specified as a QName. If it has a prefix,
|
|
* then the prefix is expanded into a URI reference using the namespace declarations
|
|
* in effect on the attribute in which the name occurs. The expanded name
|
|
* consisting of the local part of the name and the possibly null URI reference
|
|
* is used as the name of the object. The default namespace is not used for
|
|
* unprefixed names."
|
|
* @xsl.usage general
|
|
*/
|
|
public class QName implements java.io.Serializable
|
|
{
|
|
static final long serialVersionUID = 467434581652829920L;
|
|
|
|
/**
|
|
* The local name.
|
|
* @serial
|
|
*/
|
|
protected String _localName;
|
|
|
|
/**
|
|
* The namespace URI.
|
|
* @serial
|
|
*/
|
|
protected String _namespaceURI;
|
|
|
|
/**
|
|
* The namespace prefix.
|
|
* @serial
|
|
*/
|
|
protected String _prefix;
|
|
|
|
/**
|
|
* The XML namespace.
|
|
*/
|
|
public static final String S_XMLNAMESPACEURI =
|
|
"http://www.w3.org/XML/1998/namespace";
|
|
|
|
/**
|
|
* The cached hashcode, which is calculated at construction time.
|
|
* @serial
|
|
*/
|
|
private int m_hashCode;
|
|
|
|
/**
|
|
* Constructs an empty QName.
|
|
* 20001019: Try making this public, to support Serializable? -- JKESS
|
|
*/
|
|
public QName(){}
|
|
|
|
/**
|
|
* Constructs a new QName with the specified namespace URI and
|
|
* local name.
|
|
*
|
|
* @param namespaceURI The namespace URI if known, or null
|
|
* @param localName The local name
|
|
*/
|
|
public QName(String namespaceURI, String localName)
|
|
{
|
|
this(namespaceURI, localName, false);
|
|
}
|
|
|
|
/**
|
|
* Constructs a new QName with the specified namespace URI and
|
|
* local name.
|
|
*
|
|
* @param namespaceURI The namespace URI if known, or null
|
|
* @param localName The local name
|
|
* @param validate If true the new QName will be validated and an IllegalArgumentException will
|
|
* be thrown if it is invalid.
|
|
*/
|
|
public QName(String namespaceURI, String localName, boolean validate)
|
|
{
|
|
|
|
// This check was already here. So, for now, I will not add it to the validation
|
|
// that is done when the validate parameter is true.
|
|
if (localName == null)
|
|
throw new IllegalArgumentException(XMLMessages.createXMLMessage(
|
|
XMLErrorResources.ER_ARG_LOCALNAME_NULL, null)); //"Argument 'localName' is null");
|
|
|
|
if (validate)
|
|
{
|
|
if (!XML11Char.isXML11ValidNCName(localName))
|
|
{
|
|
throw new IllegalArgumentException(XMLMessages.createXMLMessage(
|
|
XMLErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
|
|
}
|
|
}
|
|
|
|
_namespaceURI = namespaceURI;
|
|
_localName = localName;
|
|
m_hashCode = toString().hashCode();
|
|
}
|
|
|
|
/**
|
|
* Constructs a new QName with the specified namespace URI, prefix
|
|
* and local name.
|
|
*
|
|
* @param namespaceURI The namespace URI if known, or null
|
|
* @param prefix The namespace prefix is known, or null
|
|
* @param localName The local name
|
|
*
|
|
*/
|
|
public QName(String namespaceURI, String prefix, String localName)
|
|
{
|
|
this(namespaceURI, prefix, localName, false);
|
|
}
|
|
|
|
/**
|
|
* Constructs a new QName with the specified namespace URI, prefix
|
|
* and local name.
|
|
*
|
|
* @param namespaceURI The namespace URI if known, or null
|
|
* @param prefix The namespace prefix is known, or null
|
|
* @param localName The local name
|
|
* @param validate If true the new QName will be validated and an IllegalArgumentException will
|
|
* be thrown if it is invalid.
|
|
*/
|
|
public QName(String namespaceURI, String prefix, String localName, boolean validate)
|
|
{
|
|
|
|
// This check was already here. So, for now, I will not add it to the validation
|
|
// that is done when the validate parameter is true.
|
|
if (localName == null)
|
|
throw new IllegalArgumentException(XMLMessages.createXMLMessage(
|
|
XMLErrorResources.ER_ARG_LOCALNAME_NULL, null)); //"Argument 'localName' is null");
|
|
|
|
if (validate)
|
|
{
|
|
if (!XML11Char.isXML11ValidNCName(localName))
|
|
{
|
|
throw new IllegalArgumentException(XMLMessages.createXMLMessage(
|
|
XMLErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
|
|
}
|
|
|
|
if ((null != prefix) && (!XML11Char.isXML11ValidNCName(prefix)))
|
|
{
|
|
throw new IllegalArgumentException(XMLMessages.createXMLMessage(
|
|
XMLErrorResources.ER_ARG_PREFIX_INVALID,null )); //"Argument 'prefix' not a valid NCName");
|
|
}
|
|
|
|
}
|
|
_namespaceURI = namespaceURI;
|
|
_prefix = prefix;
|
|
_localName = localName;
|
|
m_hashCode = toString().hashCode();
|
|
}
|
|
|
|
/**
|
|
* Construct a QName from a string, without namespace resolution. Good
|
|
* for a few odd cases.
|
|
*
|
|
* @param localName Local part of qualified name
|
|
*
|
|
*/
|
|
public QName(String localName)
|
|
{
|
|
this(localName, false);
|
|
}
|
|
|
|
/**
|
|
* Construct a QName from a string, without namespace resolution. Good
|
|
* for a few odd cases.
|
|
*
|
|
* @param localName Local part of qualified name
|
|
* @param validate If true the new QName will be validated and an IllegalArgumentException will
|
|
* be thrown if it is invalid.
|
|
*/
|
|
public QName(String localName, boolean validate)
|
|
{
|
|
|
|
// This check was already here. So, for now, I will not add it to the validation
|
|
// that is done when the validate parameter is true.
|
|
if (localName == null)
|
|
throw new IllegalArgumentException(XMLMessages.createXMLMessage(
|
|
XMLErrorResources.ER_ARG_LOCALNAME_NULL, null)); //"Argument 'localName' is null");
|
|
|
|
if (validate)
|
|
{
|
|
if (!XML11Char.isXML11ValidNCName(localName))
|
|
{
|
|
throw new IllegalArgumentException(XMLMessages.createXMLMessage(
|
|
XMLErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
|
|
}
|
|
}
|
|
_namespaceURI = null;
|
|
_localName = localName;
|
|
m_hashCode = toString().hashCode();
|
|
}
|
|
|
|
/**
|
|
* Construct a QName from a string, resolving the prefix
|
|
* using the given namespace stack. The default namespace is
|
|
* not resolved.
|
|
*
|
|
* @param qname Qualified name to resolve
|
|
* @param namespaces Namespace stack to use to resolve namespace
|
|
*/
|
|
public QName(String qname, Stack namespaces)
|
|
{
|
|
this(qname, namespaces, false);
|
|
}
|
|
|
|
/**
|
|
* Construct a QName from a string, resolving the prefix
|
|
* using the given namespace stack. The default namespace is
|
|
* not resolved.
|
|
*
|
|
* @param qname Qualified name to resolve
|
|
* @param namespaces Namespace stack to use to resolve namespace
|
|
* @param validate If true the new QName will be validated and an IllegalArgumentException will
|
|
* be thrown if it is invalid.
|
|
*/
|
|
public QName(String qname, Stack namespaces, boolean validate)
|
|
{
|
|
|
|
String namespace = null;
|
|
String prefix = null;
|
|
int indexOfNSSep = qname.indexOf(':');
|
|
|
|
if (indexOfNSSep > 0)
|
|
{
|
|
prefix = qname.substring(0, indexOfNSSep);
|
|
|
|
if (prefix.equals("xml"))
|
|
{
|
|
namespace = S_XMLNAMESPACEURI;
|
|
}
|
|
// Do we want this?
|
|
else if (prefix.equals("xmlns"))
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
int depth = namespaces.size();
|
|
|
|
for (int i = depth - 1; i >= 0; i--)
|
|
{
|
|
NameSpace ns = (NameSpace) namespaces.elementAt(i);
|
|
|
|
while (null != ns)
|
|
{
|
|
if ((null != ns.m_prefix) && prefix.equals(ns.m_prefix))
|
|
{
|
|
namespace = ns.m_uri;
|
|
i = -1;
|
|
|
|
break;
|
|
}
|
|
|
|
ns = ns.m_next;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (null == namespace)
|
|
{
|
|
throw new RuntimeException(
|
|
XMLMessages.createXMLMessage(
|
|
XMLErrorResources.ER_PREFIX_MUST_RESOLVE,
|
|
new Object[]{ prefix })); //"Prefix must resolve to a namespace: "+prefix);
|
|
}
|
|
}
|
|
|
|
_localName = (indexOfNSSep < 0)
|
|
? qname : qname.substring(indexOfNSSep + 1);
|
|
|
|
if (validate)
|
|
{
|
|
if ((_localName == null) || (!XML11Char.isXML11ValidNCName(_localName)))
|
|
{
|
|
throw new IllegalArgumentException(XMLMessages.createXMLMessage(
|
|
XMLErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
|
|
}
|
|
}
|
|
_namespaceURI = namespace;
|
|
_prefix = prefix;
|
|
m_hashCode = toString().hashCode();
|
|
}
|
|
|
|
/**
|
|
* Construct a QName from a string, resolving the prefix
|
|
* using the given namespace context and prefix resolver.
|
|
* The default namespace is not resolved.
|
|
*
|
|
* @param qname Qualified name to resolve
|
|
* @param namespaceContext Namespace Context to use
|
|
* @param resolver Prefix resolver for this context
|
|
*/
|
|
public QName(String qname, Element namespaceContext,
|
|
PrefixResolver resolver)
|
|
{
|
|
this(qname, namespaceContext, resolver, false);
|
|
}
|
|
|
|
/**
|
|
* Construct a QName from a string, resolving the prefix
|
|
* using the given namespace context and prefix resolver.
|
|
* The default namespace is not resolved.
|
|
*
|
|
* @param qname Qualified name to resolve
|
|
* @param namespaceContext Namespace Context to use
|
|
* @param resolver Prefix resolver for this context
|
|
* @param validate If true the new QName will be validated and an IllegalArgumentException will
|
|
* be thrown if it is invalid.
|
|
*/
|
|
public QName(String qname, Element namespaceContext,
|
|
PrefixResolver resolver, boolean validate)
|
|
{
|
|
|
|
_namespaceURI = null;
|
|
|
|
int indexOfNSSep = qname.indexOf(':');
|
|
|
|
if (indexOfNSSep > 0)
|
|
{
|
|
if (null != namespaceContext)
|
|
{
|
|
String prefix = qname.substring(0, indexOfNSSep);
|
|
|
|
_prefix = prefix;
|
|
|
|
if (prefix.equals("xml"))
|
|
{
|
|
_namespaceURI = S_XMLNAMESPACEURI;
|
|
}
|
|
|
|
// Do we want this?
|
|
else if (prefix.equals("xmlns"))
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
_namespaceURI = resolver.getNamespaceForPrefix(prefix,
|
|
namespaceContext);
|
|
}
|
|
|
|
if (null == _namespaceURI)
|
|
{
|
|
throw new RuntimeException(
|
|
XMLMessages.createXMLMessage(
|
|
XMLErrorResources.ER_PREFIX_MUST_RESOLVE,
|
|
new Object[]{ prefix })); //"Prefix must resolve to a namespace: "+prefix);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// TODO: error or warning...
|
|
}
|
|
}
|
|
|
|
_localName = (indexOfNSSep < 0)
|
|
? qname : qname.substring(indexOfNSSep + 1);
|
|
|
|
if (validate)
|
|
{
|
|
if ((_localName == null) || (!XML11Char.isXML11ValidNCName(_localName)))
|
|
{
|
|
throw new IllegalArgumentException(XMLMessages.createXMLMessage(
|
|
XMLErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
|
|
}
|
|
}
|
|
|
|
m_hashCode = toString().hashCode();
|
|
}
|
|
|
|
|
|
/**
|
|
* Construct a QName from a string, resolving the prefix
|
|
* using the given namespace stack. The default namespace is
|
|
* not resolved.
|
|
*
|
|
* @param qname Qualified name to resolve
|
|
* @param resolver Prefix resolver for this context
|
|
*/
|
|
public QName(String qname, PrefixResolver resolver)
|
|
{
|
|
this(qname, resolver, false);
|
|
}
|
|
|
|
/**
|
|
* Construct a QName from a string, resolving the prefix
|
|
* using the given namespace stack. The default namespace is
|
|
* not resolved.
|
|
*
|
|
* @param qname Qualified name to resolve
|
|
* @param resolver Prefix resolver for this context
|
|
* @param validate If true the new QName will be validated and an IllegalArgumentException will
|
|
* be thrown if it is invalid.
|
|
*/
|
|
public QName(String qname, PrefixResolver resolver, boolean validate)
|
|
{
|
|
|
|
String prefix = null;
|
|
_namespaceURI = null;
|
|
|
|
int indexOfNSSep = qname.indexOf(':');
|
|
|
|
if (indexOfNSSep > 0)
|
|
{
|
|
prefix = qname.substring(0, indexOfNSSep);
|
|
|
|
if (prefix.equals("xml"))
|
|
{
|
|
_namespaceURI = S_XMLNAMESPACEURI;
|
|
}
|
|
else
|
|
{
|
|
_namespaceURI = resolver.getNamespaceForPrefix(prefix);
|
|
}
|
|
|
|
if (null == _namespaceURI)
|
|
{
|
|
throw new RuntimeException(
|
|
XMLMessages.createXMLMessage(
|
|
XMLErrorResources.ER_PREFIX_MUST_RESOLVE,
|
|
new Object[]{ prefix })); //"Prefix must resolve to a namespace: "+prefix);
|
|
}
|
|
_localName = qname.substring(indexOfNSSep + 1);
|
|
}
|
|
else if (indexOfNSSep == 0)
|
|
{
|
|
throw new RuntimeException(
|
|
XMLMessages.createXMLMessage(
|
|
XMLErrorResources.ER_NAME_CANT_START_WITH_COLON,
|
|
null));
|
|
}
|
|
else
|
|
{
|
|
_localName = qname;
|
|
}
|
|
|
|
if (validate)
|
|
{
|
|
if ((_localName == null) || (!XML11Char.isXML11ValidNCName(_localName)))
|
|
{
|
|
throw new IllegalArgumentException(XMLMessages.createXMLMessage(
|
|
XMLErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
|
|
}
|
|
}
|
|
|
|
|
|
m_hashCode = toString().hashCode();
|
|
_prefix = prefix;
|
|
}
|
|
|
|
/**
|
|
* Returns the namespace URI. Returns null if the namespace URI
|
|
* is not known.
|
|
*
|
|
* @return The namespace URI, or null
|
|
*/
|
|
public String getNamespaceURI()
|
|
{
|
|
return _namespaceURI;
|
|
}
|
|
|
|
/**
|
|
* Returns the namespace prefix. Returns null if the namespace
|
|
* prefix is not known.
|
|
*
|
|
* @return The namespace prefix, or null
|
|
*/
|
|
public String getPrefix()
|
|
{
|
|
return _prefix;
|
|
}
|
|
|
|
/**
|
|
* Returns the local part of the qualified name.
|
|
*
|
|
* @return The local part of the qualified name
|
|
*/
|
|
public String getLocalName()
|
|
{
|
|
return _localName;
|
|
}
|
|
|
|
/**
|
|
* Return the string representation of the qualified name, using the
|
|
* prefix if available, or the '{ns}foo' notation if not. Performs
|
|
* string concatenation, so beware of performance issues.
|
|
*
|
|
* @return the string representation of the namespace
|
|
*/
|
|
public String toString()
|
|
{
|
|
|
|
return _prefix != null
|
|
? (_prefix + ":" + _localName)
|
|
: (_namespaceURI != null
|
|
? ("{"+_namespaceURI + "}" + _localName) : _localName);
|
|
}
|
|
|
|
/**
|
|
* Return the string representation of the qualified name using the
|
|
* the '{ns}foo' notation. Performs
|
|
* string concatenation, so beware of performance issues.
|
|
*
|
|
* @return the string representation of the namespace
|
|
*/
|
|
public String toNamespacedString()
|
|
{
|
|
|
|
return (_namespaceURI != null
|
|
? ("{"+_namespaceURI + "}" + _localName) : _localName);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the namespace of the qualified name.
|
|
*
|
|
* @return the namespace URI of the qualified name
|
|
*/
|
|
public String getNamespace()
|
|
{
|
|
return getNamespaceURI();
|
|
}
|
|
|
|
/**
|
|
* Get the local part of the qualified name.
|
|
*
|
|
* @return the local part of the qualified name
|
|
*/
|
|
public String getLocalPart()
|
|
{
|
|
return getLocalName();
|
|
}
|
|
|
|
/**
|
|
* Return the cached hashcode of the qualified name.
|
|
*
|
|
* @return the cached hashcode of the qualified name
|
|
*/
|
|
public int hashCode()
|
|
{
|
|
return m_hashCode;
|
|
}
|
|
|
|
/**
|
|
* Override equals and agree that we're equal if
|
|
* the passed object is a string and it matches
|
|
* the name of the arg.
|
|
*
|
|
* @param ns Namespace URI to compare to
|
|
* @param localPart Local part of qualified name to compare to
|
|
*
|
|
* @return True if the local name and uri match
|
|
*/
|
|
public boolean equals(String ns, String localPart)
|
|
{
|
|
|
|
String thisnamespace = getNamespaceURI();
|
|
|
|
return getLocalName().equals(localPart)
|
|
&& (((null != thisnamespace) && (null != ns))
|
|
? thisnamespace.equals(ns)
|
|
: ((null == thisnamespace) && (null == ns)));
|
|
}
|
|
|
|
/**
|
|
* Override equals and agree that we're equal if
|
|
* the passed object is a QName and it matches
|
|
* the name of the arg.
|
|
*
|
|
* @return True if the qualified names are equal
|
|
*/
|
|
public boolean equals(Object object)
|
|
{
|
|
|
|
if (object == this)
|
|
return true;
|
|
|
|
if (object instanceof QName) {
|
|
QName qname = (QName) object;
|
|
String thisnamespace = getNamespaceURI();
|
|
String thatnamespace = qname.getNamespaceURI();
|
|
|
|
return getLocalName().equals(qname.getLocalName())
|
|
&& (((null != thisnamespace) && (null != thatnamespace))
|
|
? thisnamespace.equals(thatnamespace)
|
|
: ((null == thisnamespace) && (null == thatnamespace)));
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Given a string, create and return a QName object
|
|
*
|
|
*
|
|
* @param name String to use to create QName
|
|
*
|
|
* @return a QName object
|
|
*/
|
|
public static QName getQNameFromString(String name)
|
|
{
|
|
|
|
StringTokenizer tokenizer = new StringTokenizer(name, "{}", false);
|
|
QName qname;
|
|
String s1 = tokenizer.nextToken();
|
|
String s2 = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
|
|
|
|
if (null == s2)
|
|
qname = new QName(null, s1);
|
|
else
|
|
qname = new QName(s1, s2);
|
|
|
|
return qname;
|
|
}
|
|
|
|
/**
|
|
* This function tells if a raw attribute name is a
|
|
* xmlns attribute.
|
|
*
|
|
* @param attRawName Raw name of attribute
|
|
*
|
|
* @return True if the attribute starts with or is equal to xmlns
|
|
*/
|
|
public static boolean isXMLNSDecl(String attRawName)
|
|
{
|
|
|
|
return (attRawName.startsWith("xmlns")
|
|
&& (attRawName.equals("xmlns")
|
|
|| attRawName.startsWith("xmlns:")));
|
|
}
|
|
|
|
/**
|
|
* This function tells if a raw attribute name is a
|
|
* xmlns attribute.
|
|
*
|
|
* @param attRawName Raw name of attribute
|
|
*
|
|
* @return Prefix of attribute
|
|
*/
|
|
public static String getPrefixFromXMLNSDecl(String attRawName)
|
|
{
|
|
|
|
int index = attRawName.indexOf(':');
|
|
|
|
return (index >= 0) ? attRawName.substring(index + 1) : "";
|
|
}
|
|
|
|
/**
|
|
* Returns the local name of the given node.
|
|
*
|
|
* @param qname Input name
|
|
*
|
|
* @return Local part of the name if prefixed, or the given name if not
|
|
*/
|
|
public static String getLocalPart(String qname)
|
|
{
|
|
|
|
int index = qname.indexOf(':');
|
|
|
|
return (index < 0) ? qname : qname.substring(index + 1);
|
|
}
|
|
|
|
/**
|
|
* Returns the local name of the given node.
|
|
*
|
|
* @param qname Input name
|
|
*
|
|
* @return Prefix of name or empty string if none there
|
|
*/
|
|
public static String getPrefixPart(String qname)
|
|
{
|
|
|
|
int index = qname.indexOf(':');
|
|
|
|
return (index >= 0) ? qname.substring(0, index) : "";
|
|
}
|
|
}
|