1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 #if !defined(XALANQNAME_HEADER_GUARD_1357924680)
19 #define XALANQNAME_HEADER_GUARD_1357924680
20 
21 
22 
23 // Base header file.  Must be first.
24 #include <xalanc/XPath/XPathDefinitions.hpp>
25 
26 
27 
28 #include <xalanc/Include/XalanMap.hpp>
29 #include <xalanc/Include/XalanDeque.hpp>
30 #include <xalanc/Include/STLHelper.hpp>
31 
32 
33 
34 #include <xalanc/XalanDOM/XalanDOMString.hpp>
35 
36 
37 
38 #include <xalanc/PlatformSupport/DOMStringHelper.hpp>
39 #include <xalanc/PlatformSupport/PrefixResolver.hpp>
40 
41 
42 
43 #include <xalanc/XPath/NameSpace.hpp>
44 #include <xalanc/XPath/XalanXPathException.hpp>
45 
46 
47 
48 namespace XALAN_CPP_NAMESPACE {
49 
50 
51 
52 class XalanElement;
53 class XPathEnvSupport;
54 
55 
56 
57 /**
58  * Class to represent a qualified name. The name of an internal XSLT object,
59  * specifically a named template (see [7 Named Templates]), a mode (see [6.7 Modes]),
60  * an attribute set (see [8.1.4 Named Attribute Sets]), a key (see [14.2 Keys]),
61  * a locale (see [14.3 Number Formatting]), a variable or a parameter (see
62  * [12 Variables and Parameters]) is specified as a QName. If it has a prefix,
63  * then the prefix is expanded into a URI reference using the namespace declarations
64  * in effect on the attribute in which the name occurs. The expanded name
65  * consisting of the local part of the name and the possibly null URI reference
66  * is used as the name of the object. The default namespace is not used for
67  * unprefixed names.
68  */
69 
70 class XALAN_XPATH_EXPORT XalanQName
71 {
72 public:
73 
74     typedef XalanDeque<NameSpace, ConstructWithMemoryManagerTraits<NameSpace> >
75                                                             NamespaceVectorType;
76     typedef XalanDeque<NamespaceVectorType, ConstructWithMemoryManagerTraits<NamespaceVectorType> >
77                                                             NamespacesStackType;
78 
79     /**
80      * Construct an empty XalanQName.
81      *
82      */
83     explicit
XalanQName()84     XalanQName()
85     {
86     }
87 
88     virtual
~XalanQName()89     ~XalanQName()
90     {
91     }
92 
XalanQName(const XalanQName &)93     XalanQName(const XalanQName&)
94     {
95     }
96 
97     /**
98      * Retrieve the local part of qualified name.
99      *
100      * @return local part string
101      */
102     virtual const XalanDOMString&
103     getLocalPart() const = 0;
104 
105     /**
106      * Retrieve the namespace of qualified name.
107      *
108      * @return namespace string
109      */
110     virtual const XalanDOMString&
111     getNamespace() const = 0;
112 
113     /**
114      * Determine if the qualified name is valid.
115      *
116      * @return true if the instance is a valid QName, false if not.
117      */
118     bool
isValid() const119     isValid() const
120     {
121         return isValidNCName(getLocalPart());
122     }
123 
124     /**
125      * Whether the qualified name is empty.
126      *
127      * @return true if namespace and local part are both empty
128      */
129     bool
isEmpty() const130     isEmpty() const
131     {
132         return getNamespace().empty() && getLocalPart().empty();
133     }
134 
135     /**
136      * Override equals and agree that we're equal if the passed object is a
137      * string and it matches the name of the arg.
138      *
139      * @param theRHS namespace to compare
140      * @return true if namespace and local part are both empty
141      */
142     bool
equals(const XalanQName & theRHS) const143     equals(const XalanQName&    theRHS) const
144     {
145         // Note that we do not use our member variables here.  See
146         // class QNameReference for details...
147         return getLocalPart() == theRHS.getLocalPart() &&
148                getNamespace() == theRHS.getNamespace();
149     }
150 
151     /**
152      * Format the QName using the notation "{namespace-uri}local-part" or
153      * "local-part" if the namespace URI is empty.  The result is appended
154      * to the provided string.
155      *
156      * @param theString The string to format with the
157      * @return A reference to the parameter.
158      */
159     XalanDOMString&
160     format(XalanDOMString&  theString) const;
161 
162     size_t
hash() const163     hash() const
164     {
165         return getLocalPart().hash() % (getNamespace().hash() + 1);
166     }
167 
168     class XALAN_XPATH_EXPORT PrefixResolverProxy : public PrefixResolver
169     {
170     public:
171 
172         /**
173          * Construct a PrefixResolver from a NamespacesStackType
174          * instance.
175          *
176          * @param theStack The stack to use for prefix resolution
177          * @param theURI The namespace URI of the resolver, if any.  Only a reference is kept, so this cannot be a temporary
178          * @return pointer to the string value if found, otherwise 0.
179          */
180         PrefixResolverProxy(
181                 const NamespacesStackType&  theStack,
182                 const XalanDOMString&       theURI);
183 
184         virtual
185         ~PrefixResolverProxy();
186 
187         virtual const XalanDOMString*
188         getNamespaceForPrefix(const XalanDOMString&     prefix) const;
189 
190         virtual const XalanDOMString&
191         getURI() const;
192 
193     private:
194 
195         const NamespacesStackType&  m_stack;
196 
197         const XalanDOMString&       m_uri;
198     };
199 
200     /**
201      * Get the namespace for a prefix by searching a vector of namespaces.
202      *
203      * @param namespaces vector of namespaces to search
204      * @param prefix     namespace prefix to find
205      * @return pointer to the string value if found, otherwise null.
206      */
207     static const XalanDOMString*
208     getNamespaceForPrefix(
209             const NamespaceVectorType&  namespaces,
210             const XalanDOMString&       prefix);
211 
212     /**
213      * Get the namespace for a prefix by searching a stack of namespace
214      * vectors.
215      *
216      * @param nsStack stack of namespace vectors to search
217      * @param prefix  namespace prefix to find
218      * @return pointer to the string value if found, otherwise null.
219      */
220     static const XalanDOMString*
221     getNamespaceForPrefix(
222             const NamespacesStackType&  nsStack,
223             const XalanDOMString&       prefix);
224 
225     static const XalanDOMString*
226     getNamespaceForPrefix(
227             const NamespacesStackType&  nsStack,
228             const XalanDOMChar*         prefix);
229 
230     /**
231      * Get the namespace for a prefix by searching a range of iterators.
232      * The search is done in reverse, from the end of the range to the
233      * beginning.
234      *
235      * @param theBegin The beginning iterator for the range
236      * @param theBegin The ending iterator for the range
237      * @param prefix  namespace prefix to find
238      * @return pointer to the string value if found, otherwise null.
239      */
240     static const XalanDOMString*
241     getNamespaceForPrefix(
242             NamespacesStackType::const_iterator     theBegin,
243             NamespacesStackType::const_iterator     theEnd,
244             const XalanDOMString&                   prefix);
245 
246     /**
247      * Get the prefix for a namespace by searching a vector of namespaces.
248      *
249      * @param namespaces vector of namespaces to search
250      * @param uri        URI string for namespace to find
251      * @param reverse    true to search vector from last to first, default true
252      * @return pointer to the string value if found, otherwise null.
253      */
254     static const XalanDOMString*
255     getPrefixForNamespace(
256             const NamespaceVectorType&  namespaces,
257             const XalanDOMString&       uri);
258 
259     static const XalanDOMString*
260     getNamespaceForPrefix(
261             const NamespaceVectorType&  namespaces,
262             const XalanDOMChar*         prefix);
263 
264     /**
265      * Get the prefix for a namespace by searching a stack of namespace
266      * vectors.
267      *
268      * @param nsStack stack of namespace vectors to search
269      * @param uri     URI string for namespace to find
270      * @return pointer to the string value if found, otherwise null.
271      */
272     static const XalanDOMString*
273     getPrefixForNamespace(
274             const NamespacesStackType&  nsStack,
275             const XalanDOMString&       uri);
276 
277     /**
278      * Get the prefix for a namespace by searching a range of iterators.
279      * The search is done in reverse, from the end of the range to the
280      * beginning.
281      *
282      * @param theBegin The beginning iterator for the range to search
283      * @param theBegin The ending iterator for the range to search
284      * @param uri     URI string for namespace to find
285      * @return pointer to the string value if found, otherwise null.
286      */
287     static const XalanDOMString*
288     getPrefixForNamespace(
289             NamespacesStackType::const_iterator     theBegin,
290             NamespacesStackType::const_iterator     theEnd,
291             const XalanDOMString&                   uri);
292 
293     static const XalanDOMString*
294     getNamespaceForPrefix(
295             NamespacesStackType::const_iterator     theBegin,
296             NamespacesStackType::const_iterator     theEnd,
297             const XalanDOMChar*                     prefix);
298     /**
299      * Determine if the string supplied satisfies the grammar for
300      * an XML NCName.
301      *
302      * @param theNCName The string to check
303      * @return bool true if the string is a valid NCName, false if not.
304      */
305     static bool
306     isValidNCName(const XalanDOMString&     theNCName);
307 
308     /**
309      * Determine if the string supplied satisfies the grammar for
310      * an XML NCName.
311      *
312      * @param theNCName The string to check
313      * @param theLength The length of the string
314      * @return bool true if the string is a valid NCName, false if not
315      */
316     static bool
317     isValidNCName(
318             const XalanDOMChar*         theNCName,
319             XalanDOMString::size_type   theLength = XalanDOMString::npos);
320 
321     /**
322      * Determine if the string supplied satisfies the grammar for
323      * an XML QName.  Note that this function does not determine
324      * if any supplied prefix is bound to a namespace URI
325      *
326      * @param theQName The string to check
327      * @return bool true if the string is a valid QName, false if not
328      */
329     static bool
330     isValidQName(const XalanDOMString&  theQName);
331 
332     /**
333      * Determine if the string supplied satisfies the grammar for
334      * an XML QName.  Note that this function does not determine
335      * if any supplied prefix is bound to a namespace URI
336      *
337      * @param theQName The string to check
338      * @param theLength The length of the string
339      * @return bool true if the string is a valid QName, false if not
340      */
341     static bool
342     isValidQName(
343             const XalanDOMChar*         theQName,
344             XalanDOMString::size_type   theLength = XalanDOMString::npos);
345 
346     class InvalidQNameException : public XalanXPathException
347     {
348     public:
349 
350         /**
351          * Constructor
352          *
353          * @param theQName The QName string that is not valid.
354          * @param theQNameLength The length of the string.
355          * @param theResult A temporary string for loading the error message.
356          */
357         InvalidQNameException(
358                 const XalanDOMChar*         theQName,
359                 XalanDOMString::size_type   theQNameLength,
360                 XalanDOMString&             theResult,
361                 const Locator*              theLocator);
362 
363         /**
364          * Constructor
365          *
366          * @param theMessage The message for the exception
367          * @param theManager The MemoryManager instance to use when constructing the exception
368          */
369         InvalidQNameException(
370                 const XalanDOMString&   theMessage,
371                 MemoryManager&          theManager,
372                 const Locator*          theLocator);
373 
374         InvalidQNameException(const InvalidQNameException&  other);
375 
376         virtual
377         ~InvalidQNameException();
378 
379         virtual const XalanDOMChar*
380         getType() const;
381 
382     private:
383 
384         static const XalanDOMString&
385         format(
386                 const XalanDOMChar*         theQName,
387                 XalanDOMString::size_type   theQNameLength,
388                 XalanDOMString&             theResult);
389     };
390 
391 protected:
392 
393     static const XalanDOMString     s_emptyString;
394 };
395 
396 
397 inline bool
operator ==(const XalanQName & theLHS,const XalanQName & theRHS)398 operator==(
399             const XalanQName&   theLHS,
400             const XalanQName&   theRHS)
401 {
402     return theLHS.equals(theRHS);
403 }
404 
405 
406 
407 inline bool
operator !=(const XalanQName & theLHS,const XalanQName & theRHS)408 operator!=(
409             const XalanQName&   theLHS,
410             const XalanQName&   theRHS)
411 {
412     return !(theLHS == theRHS);
413 }
414 
415 
416 
417 inline bool
operator <(const XalanQName & theLHS,const XalanQName & theRHS)418 operator<(
419             const XalanQName&   theLHS,
420             const XalanQName&   theRHS)
421 {
422     if (theLHS.getNamespace() < theRHS.getNamespace())
423     {
424         return true;
425     }
426     else if (equals(theLHS.getNamespace(), theRHS.getNamespace()))
427     {
428         return theLHS.getLocalPart() < theRHS.getLocalPart();
429     }
430     else
431     {
432         return false;
433     }
434 }
435 
436 template<>
437 struct XalanMapKeyTraits<XalanQName>
438 {
439     typedef XalanHashMemberReference<XalanQName>        Hasher;
440     typedef std::equal_to<XalanQName>    Comparator;
441 };
442 
443 template<>
444 struct XalanMapKeyTraits<const XalanQName*>
445 {
446     typedef XalanHashMemberPointer<XalanQName>      Hasher;
447     typedef pointer_equal<XalanQName>               Comparator;
448 };
449 
450 
451 }
452 
453 
454 
455 #endif  // XALANQNAME_HEADER_GUARD_1357924680
456