/projects/jre-1.6.0/src/com/sun/org/apache/xml/internal/utils/QName.java
Java | 707 lines | 343 code | 94 blank | 270 comment | 78 complexity | 117db5973abf1bbad4667054b2a5404e MD5 | raw file
1/*
2 * Copyright 1999-2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16/*
17 * $Id: QName.java,v 1.2.4.1 2005/09/15 08:15:52 suresh_emailid Exp $
18 */
19package com.sun.org.apache.xml.internal.utils;
20
21import java.util.Stack;
22import java.util.StringTokenizer;
23
24import com.sun.org.apache.xml.internal.res.XMLErrorResources;
25import com.sun.org.apache.xml.internal.res.XMLMessages;
26
27import org.w3c.dom.Element;
28
29/**
30 * Class to represent a qualified name: "The name of an internal XSLT object,
31 * specifically a named template (see [7 Named Templates]), a mode (see [6.7 Modes]),
32 * an attribute set (see [8.1.4 Named Attribute Sets]), a key (see [14.2 Keys]),
33 * a locale (see [14.3 Number Formatting]), a variable or a parameter (see
34 * [12 Variables and Parameters]) is specified as a QName. If it has a prefix,
35 * then the prefix is expanded into a URI reference using the namespace declarations
36 * in effect on the attribute in which the name occurs. The expanded name
37 * consisting of the local part of the name and the possibly null URI reference
38 * is used as the name of the object. The default namespace is not used for
39 * unprefixed names."
40 * @xsl.usage general
41 */
42public class QName implements java.io.Serializable
43{
44 static final long serialVersionUID = 467434581652829920L;
45
46 /**
47 * The local name.
48 * @serial
49 */
50 protected String _localName;
51
52 /**
53 * The namespace URI.
54 * @serial
55 */
56 protected String _namespaceURI;
57
58 /**
59 * The namespace prefix.
60 * @serial
61 */
62 protected String _prefix;
63
64 /**
65 * The XML namespace.
66 */
67 public static final String S_XMLNAMESPACEURI =
68 "http://www.w3.org/XML/1998/namespace";
69
70 /**
71 * The cached hashcode, which is calculated at construction time.
72 * @serial
73 */
74 private int m_hashCode;
75
76 /**
77 * Constructs an empty QName.
78 * 20001019: Try making this public, to support Serializable? -- JKESS
79 */
80 public QName(){}
81
82 /**
83 * Constructs a new QName with the specified namespace URI and
84 * local name.
85 *
86 * @param namespaceURI The namespace URI if known, or null
87 * @param localName The local name
88 */
89 public QName(String namespaceURI, String localName)
90 {
91 this(namespaceURI, localName, false);
92 }
93
94 /**
95 * Constructs a new QName with the specified namespace URI and
96 * local name.
97 *
98 * @param namespaceURI The namespace URI if known, or null
99 * @param localName The local name
100 * @param validate If true the new QName will be validated and an IllegalArgumentException will
101 * be thrown if it is invalid.
102 */
103 public QName(String namespaceURI, String localName, boolean validate)
104 {
105
106 // This check was already here. So, for now, I will not add it to the validation
107 // that is done when the validate parameter is true.
108 if (localName == null)
109 throw new IllegalArgumentException(XMLMessages.createXMLMessage(
110 XMLErrorResources.ER_ARG_LOCALNAME_NULL, null)); //"Argument 'localName' is null");
111
112 if (validate)
113 {
114 if (!XML11Char.isXML11ValidNCName(localName))
115 {
116 throw new IllegalArgumentException(XMLMessages.createXMLMessage(
117 XMLErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
118 }
119 }
120
121 _namespaceURI = namespaceURI;
122 _localName = localName;
123 m_hashCode = toString().hashCode();
124 }
125
126 /**
127 * Constructs a new QName with the specified namespace URI, prefix
128 * and local name.
129 *
130 * @param namespaceURI The namespace URI if known, or null
131 * @param prefix The namespace prefix is known, or null
132 * @param localName The local name
133 *
134 */
135 public QName(String namespaceURI, String prefix, String localName)
136 {
137 this(namespaceURI, prefix, localName, false);
138 }
139
140 /**
141 * Constructs a new QName with the specified namespace URI, prefix
142 * and local name.
143 *
144 * @param namespaceURI The namespace URI if known, or null
145 * @param prefix The namespace prefix is known, or null
146 * @param localName The local name
147 * @param validate If true the new QName will be validated and an IllegalArgumentException will
148 * be thrown if it is invalid.
149 */
150 public QName(String namespaceURI, String prefix, String localName, boolean validate)
151 {
152
153 // This check was already here. So, for now, I will not add it to the validation
154 // that is done when the validate parameter is true.
155 if (localName == null)
156 throw new IllegalArgumentException(XMLMessages.createXMLMessage(
157 XMLErrorResources.ER_ARG_LOCALNAME_NULL, null)); //"Argument 'localName' is null");
158
159 if (validate)
160 {
161 if (!XML11Char.isXML11ValidNCName(localName))
162 {
163 throw new IllegalArgumentException(XMLMessages.createXMLMessage(
164 XMLErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
165 }
166
167 if ((null != prefix) && (!XML11Char.isXML11ValidNCName(prefix)))
168 {
169 throw new IllegalArgumentException(XMLMessages.createXMLMessage(
170 XMLErrorResources.ER_ARG_PREFIX_INVALID,null )); //"Argument 'prefix' not a valid NCName");
171 }
172
173 }
174 _namespaceURI = namespaceURI;
175 _prefix = prefix;
176 _localName = localName;
177 m_hashCode = toString().hashCode();
178 }
179
180 /**
181 * Construct a QName from a string, without namespace resolution. Good
182 * for a few odd cases.
183 *
184 * @param localName Local part of qualified name
185 *
186 */
187 public QName(String localName)
188 {
189 this(localName, false);
190 }
191
192 /**
193 * Construct a QName from a string, without namespace resolution. Good
194 * for a few odd cases.
195 *
196 * @param localName Local part of qualified name
197 * @param validate If true the new QName will be validated and an IllegalArgumentException will
198 * be thrown if it is invalid.
199 */
200 public QName(String localName, boolean validate)
201 {
202
203 // This check was already here. So, for now, I will not add it to the validation
204 // that is done when the validate parameter is true.
205 if (localName == null)
206 throw new IllegalArgumentException(XMLMessages.createXMLMessage(
207 XMLErrorResources.ER_ARG_LOCALNAME_NULL, null)); //"Argument 'localName' is null");
208
209 if (validate)
210 {
211 if (!XML11Char.isXML11ValidNCName(localName))
212 {
213 throw new IllegalArgumentException(XMLMessages.createXMLMessage(
214 XMLErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
215 }
216 }
217 _namespaceURI = null;
218 _localName = localName;
219 m_hashCode = toString().hashCode();
220 }
221
222 /**
223 * Construct a QName from a string, resolving the prefix
224 * using the given namespace stack. The default namespace is
225 * not resolved.
226 *
227 * @param qname Qualified name to resolve
228 * @param namespaces Namespace stack to use to resolve namespace
229 */
230 public QName(String qname, Stack namespaces)
231 {
232 this(qname, namespaces, false);
233 }
234
235 /**
236 * Construct a QName from a string, resolving the prefix
237 * using the given namespace stack. The default namespace is
238 * not resolved.
239 *
240 * @param qname Qualified name to resolve
241 * @param namespaces Namespace stack to use to resolve namespace
242 * @param validate If true the new QName will be validated and an IllegalArgumentException will
243 * be thrown if it is invalid.
244 */
245 public QName(String qname, Stack namespaces, boolean validate)
246 {
247
248 String namespace = null;
249 String prefix = null;
250 int indexOfNSSep = qname.indexOf(':');
251
252 if (indexOfNSSep > 0)
253 {
254 prefix = qname.substring(0, indexOfNSSep);
255
256 if (prefix.equals("xml"))
257 {
258 namespace = S_XMLNAMESPACEURI;
259 }
260 // Do we want this?
261 else if (prefix.equals("xmlns"))
262 {
263 return;
264 }
265 else
266 {
267 int depth = namespaces.size();
268
269 for (int i = depth - 1; i >= 0; i--)
270 {
271 NameSpace ns = (NameSpace) namespaces.elementAt(i);
272
273 while (null != ns)
274 {
275 if ((null != ns.m_prefix) && prefix.equals(ns.m_prefix))
276 {
277 namespace = ns.m_uri;
278 i = -1;
279
280 break;
281 }
282
283 ns = ns.m_next;
284 }
285 }
286 }
287
288 if (null == namespace)
289 {
290 throw new RuntimeException(
291 XMLMessages.createXMLMessage(
292 XMLErrorResources.ER_PREFIX_MUST_RESOLVE,
293 new Object[]{ prefix })); //"Prefix must resolve to a namespace: "+prefix);
294 }
295 }
296
297 _localName = (indexOfNSSep < 0)
298 ? qname : qname.substring(indexOfNSSep + 1);
299
300 if (validate)
301 {
302 if ((_localName == null) || (!XML11Char.isXML11ValidNCName(_localName)))
303 {
304 throw new IllegalArgumentException(XMLMessages.createXMLMessage(
305 XMLErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
306 }
307 }
308 _namespaceURI = namespace;
309 _prefix = prefix;
310 m_hashCode = toString().hashCode();
311 }
312
313 /**
314 * Construct a QName from a string, resolving the prefix
315 * using the given namespace context and prefix resolver.
316 * The default namespace is not resolved.
317 *
318 * @param qname Qualified name to resolve
319 * @param namespaceContext Namespace Context to use
320 * @param resolver Prefix resolver for this context
321 */
322 public QName(String qname, Element namespaceContext,
323 PrefixResolver resolver)
324 {
325 this(qname, namespaceContext, resolver, false);
326 }
327
328 /**
329 * Construct a QName from a string, resolving the prefix
330 * using the given namespace context and prefix resolver.
331 * The default namespace is not resolved.
332 *
333 * @param qname Qualified name to resolve
334 * @param namespaceContext Namespace Context to use
335 * @param resolver Prefix resolver for this context
336 * @param validate If true the new QName will be validated and an IllegalArgumentException will
337 * be thrown if it is invalid.
338 */
339 public QName(String qname, Element namespaceContext,
340 PrefixResolver resolver, boolean validate)
341 {
342
343 _namespaceURI = null;
344
345 int indexOfNSSep = qname.indexOf(':');
346
347 if (indexOfNSSep > 0)
348 {
349 if (null != namespaceContext)
350 {
351 String prefix = qname.substring(0, indexOfNSSep);
352
353 _prefix = prefix;
354
355 if (prefix.equals("xml"))
356 {
357 _namespaceURI = S_XMLNAMESPACEURI;
358 }
359
360 // Do we want this?
361 else if (prefix.equals("xmlns"))
362 {
363 return;
364 }
365 else
366 {
367 _namespaceURI = resolver.getNamespaceForPrefix(prefix,
368 namespaceContext);
369 }
370
371 if (null == _namespaceURI)
372 {
373 throw new RuntimeException(
374 XMLMessages.createXMLMessage(
375 XMLErrorResources.ER_PREFIX_MUST_RESOLVE,
376 new Object[]{ prefix })); //"Prefix must resolve to a namespace: "+prefix);
377 }
378 }
379 else
380 {
381
382 // TODO: error or warning...
383 }
384 }
385
386 _localName = (indexOfNSSep < 0)
387 ? qname : qname.substring(indexOfNSSep + 1);
388
389 if (validate)
390 {
391 if ((_localName == null) || (!XML11Char.isXML11ValidNCName(_localName)))
392 {
393 throw new IllegalArgumentException(XMLMessages.createXMLMessage(
394 XMLErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
395 }
396 }
397
398 m_hashCode = toString().hashCode();
399 }
400
401
402 /**
403 * Construct a QName from a string, resolving the prefix
404 * using the given namespace stack. The default namespace is
405 * not resolved.
406 *
407 * @param qname Qualified name to resolve
408 * @param resolver Prefix resolver for this context
409 */
410 public QName(String qname, PrefixResolver resolver)
411 {
412 this(qname, resolver, false);
413 }
414
415 /**
416 * Construct a QName from a string, resolving the prefix
417 * using the given namespace stack. The default namespace is
418 * not resolved.
419 *
420 * @param qname Qualified name to resolve
421 * @param resolver Prefix resolver for this context
422 * @param validate If true the new QName will be validated and an IllegalArgumentException will
423 * be thrown if it is invalid.
424 */
425 public QName(String qname, PrefixResolver resolver, boolean validate)
426 {
427
428 String prefix = null;
429 _namespaceURI = null;
430
431 int indexOfNSSep = qname.indexOf(':');
432
433 if (indexOfNSSep > 0)
434 {
435 prefix = qname.substring(0, indexOfNSSep);
436
437 if (prefix.equals("xml"))
438 {
439 _namespaceURI = S_XMLNAMESPACEURI;
440 }
441 else
442 {
443 _namespaceURI = resolver.getNamespaceForPrefix(prefix);
444 }
445
446 if (null == _namespaceURI)
447 {
448 throw new RuntimeException(
449 XMLMessages.createXMLMessage(
450 XMLErrorResources.ER_PREFIX_MUST_RESOLVE,
451 new Object[]{ prefix })); //"Prefix must resolve to a namespace: "+prefix);
452 }
453 _localName = qname.substring(indexOfNSSep + 1);
454 }
455 else if (indexOfNSSep == 0)
456 {
457 throw new RuntimeException(
458 XMLMessages.createXMLMessage(
459 XMLErrorResources.ER_NAME_CANT_START_WITH_COLON,
460 null));
461 }
462 else
463 {
464 _localName = qname;
465 }
466
467 if (validate)
468 {
469 if ((_localName == null) || (!XML11Char.isXML11ValidNCName(_localName)))
470 {
471 throw new IllegalArgumentException(XMLMessages.createXMLMessage(
472 XMLErrorResources.ER_ARG_LOCALNAME_INVALID,null )); //"Argument 'localName' not a valid NCName");
473 }
474 }
475
476
477 m_hashCode = toString().hashCode();
478 _prefix = prefix;
479 }
480
481 /**
482 * Returns the namespace URI. Returns null if the namespace URI
483 * is not known.
484 *
485 * @return The namespace URI, or null
486 */
487 public String getNamespaceURI()
488 {
489 return _namespaceURI;
490 }
491
492 /**
493 * Returns the namespace prefix. Returns null if the namespace
494 * prefix is not known.
495 *
496 * @return The namespace prefix, or null
497 */
498 public String getPrefix()
499 {
500 return _prefix;
501 }
502
503 /**
504 * Returns the local part of the qualified name.
505 *
506 * @return The local part of the qualified name
507 */
508 public String getLocalName()
509 {
510 return _localName;
511 }
512
513 /**
514 * Return the string representation of the qualified name, using the
515 * prefix if available, or the '{ns}foo' notation if not. Performs
516 * string concatenation, so beware of performance issues.
517 *
518 * @return the string representation of the namespace
519 */
520 public String toString()
521 {
522
523 return _prefix != null
524 ? (_prefix + ":" + _localName)
525 : (_namespaceURI != null
526 ? ("{"+_namespaceURI + "}" + _localName) : _localName);
527 }
528
529 /**
530 * Return the string representation of the qualified name using the
531 * the '{ns}foo' notation. Performs
532 * string concatenation, so beware of performance issues.
533 *
534 * @return the string representation of the namespace
535 */
536 public String toNamespacedString()
537 {
538
539 return (_namespaceURI != null
540 ? ("{"+_namespaceURI + "}" + _localName) : _localName);
541 }
542
543
544 /**
545 * Get the namespace of the qualified name.
546 *
547 * @return the namespace URI of the qualified name
548 */
549 public String getNamespace()
550 {
551 return getNamespaceURI();
552 }
553
554 /**
555 * Get the local part of the qualified name.
556 *
557 * @return the local part of the qualified name
558 */
559 public String getLocalPart()
560 {
561 return getLocalName();
562 }
563
564 /**
565 * Return the cached hashcode of the qualified name.
566 *
567 * @return the cached hashcode of the qualified name
568 */
569 public int hashCode()
570 {
571 return m_hashCode;
572 }
573
574 /**
575 * Override equals and agree that we're equal if
576 * the passed object is a string and it matches
577 * the name of the arg.
578 *
579 * @param ns Namespace URI to compare to
580 * @param localPart Local part of qualified name to compare to
581 *
582 * @return True if the local name and uri match
583 */
584 public boolean equals(String ns, String localPart)
585 {
586
587 String thisnamespace = getNamespaceURI();
588
589 return getLocalName().equals(localPart)
590 && (((null != thisnamespace) && (null != ns))
591 ? thisnamespace.equals(ns)
592 : ((null == thisnamespace) && (null == ns)));
593 }
594
595 /**
596 * Override equals and agree that we're equal if
597 * the passed object is a QName and it matches
598 * the name of the arg.
599 *
600 * @return True if the qualified names are equal
601 */
602 public boolean equals(Object object)
603 {
604
605 if (object == this)
606 return true;
607
608 if (object instanceof QName) {
609 QName qname = (QName) object;
610 String thisnamespace = getNamespaceURI();
611 String thatnamespace = qname.getNamespaceURI();
612
613 return getLocalName().equals(qname.getLocalName())
614 && (((null != thisnamespace) && (null != thatnamespace))
615 ? thisnamespace.equals(thatnamespace)
616 : ((null == thisnamespace) && (null == thatnamespace)));
617 }
618 else
619 return false;
620 }
621
622 /**
623 * Given a string, create and return a QName object
624 *
625 *
626 * @param name String to use to create QName
627 *
628 * @return a QName object
629 */
630 public static QName getQNameFromString(String name)
631 {
632
633 StringTokenizer tokenizer = new StringTokenizer(name, "{}", false);
634 QName qname;
635 String s1 = tokenizer.nextToken();
636 String s2 = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
637
638 if (null == s2)
639 qname = new QName(null, s1);
640 else
641 qname = new QName(s1, s2);
642
643 return qname;
644 }
645
646 /**
647 * This function tells if a raw attribute name is a
648 * xmlns attribute.
649 *
650 * @param attRawName Raw name of attribute
651 *
652 * @return True if the attribute starts with or is equal to xmlns
653 */
654 public static boolean isXMLNSDecl(String attRawName)
655 {
656
657 return (attRawName.startsWith("xmlns")
658 && (attRawName.equals("xmlns")
659 || attRawName.startsWith("xmlns:")));
660 }
661
662 /**
663 * This function tells if a raw attribute name is a
664 * xmlns attribute.
665 *
666 * @param attRawName Raw name of attribute
667 *
668 * @return Prefix of attribute
669 */
670 public static String getPrefixFromXMLNSDecl(String attRawName)
671 {
672
673 int index = attRawName.indexOf(':');
674
675 return (index >= 0) ? attRawName.substring(index + 1) : "";
676 }
677
678 /**
679 * Returns the local name of the given node.
680 *
681 * @param qname Input name
682 *
683 * @return Local part of the name if prefixed, or the given name if not
684 */
685 public static String getLocalPart(String qname)
686 {
687
688 int index = qname.indexOf(':');
689
690 return (index < 0) ? qname : qname.substring(index + 1);
691 }
692
693 /**
694 * Returns the local name of the given node.
695 *
696 * @param qname Input name
697 *
698 * @return Prefix of name or empty string if none there
699 */
700 public static String getPrefixPart(String qname)
701 {
702
703 int index = qname.indexOf(':');
704
705 return (index >= 0) ? qname.substring(0, index) : "";
706 }
707}