1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 //
41 //  W A R N I N G
42 //  -------------
43 //
44 // This file is not part of the Qt API.  It exists purely as an
45 // implementation detail.  This header file may change from version to
46 // version without notice, or even be removed.
47 //
48 // We mean it.
49 
50 #ifndef Patternist_QNameConstructor_H
51 #define Patternist_QNameConstructor_H
52 
53 #include <private/qsinglecontainer_p.h>
54 #include <private/qbuiltintypes_p.h>
55 #include <private/qpatternistlocale_p.h>
56 #include <private/qxpathhelper_p.h>
57 
58 QT_BEGIN_NAMESPACE
59 
60 namespace QPatternist
61 {
62     /**
63      * @short Creates an @c xs:QName value from a lexical QName using
64      * statically known namespace bindings.
65      *
66      * @see QQNameValue
67      * @see QXmlUtils
68      * @author Frans Englich <frans.englich@nokia.com>
69      * @ingroup Patternist_expressions
70      */
71     class QNameConstructor : public SingleContainer
72     {
73     public:
74 
75         QNameConstructor(const Expression::Ptr &source,
76                          const NamespaceResolver::Ptr &nsResolver);
77 
78         virtual Item evaluateSingleton(const DynamicContext::Ptr &) const;
79 
80         virtual SequenceType::List expectedOperandTypes() const;
81 
82         virtual SequenceType::Ptr staticType() const;
83 
84         virtual ExpressionVisitorResult::Ptr accept(const ExpressionVisitor::Ptr &visitor) const;
85 
86         /**
87          * Expands @p lexicalQName, which is a lexical representation of a QName such as "x:body", into
88          * a QName using @p nsResolver to supply the namespace bindings.
89          *
90          * If @p lexicalQName is lexically invalid @p InvalidQName is raised via @p context, or if
91          * no namespace binding does not exists for a prefix(if any) in @p lexicalQName, @p NoBinding
92          * is raised via @p context.
93          *
94          * If @p asForAttribute is @c true, the name is considered to be for an
95          * attribute in some way, and @p lexicalQName will not pick up the
96          * default namespace if it doesn't have a prefix.
97          *
98          * @p nsResolver is parameterized meaning the function can be instantiated with either
99          * DynamicContext or StaticContext.
100          *
101          * @see QQNameValue
102          * @see QXmlUtils
103          */
104         template<typename TReportContext,
105                  const ReportContext::ErrorCode InvalidQName,
106                  const ReportContext::ErrorCode NoBinding>
107         static
108         QXmlName expandQName(const QString &lexicalQName,
109                              const TReportContext &context,
110                              const NamespaceResolver::Ptr &nsResolver,
111                              const SourceLocationReflection *const r,
112                              const bool asForAttribute = false);
113 
114         /**
115          * Resolves the namespace prefix @p prefix to its namespace if it exists, or
116          * raised ReportContext::XPST0081 otherwise.
117          *
118          * @returns the namespace URI corresponding to @p prefix
119          */
120         static QXmlName::NamespaceCode namespaceForPrefix(const QXmlName::PrefixCode prefix,
121                                                           const StaticContext::Ptr &context,
122                                                           const SourceLocationReflection *const r);
123 
124         virtual const SourceLocationReflection *actualReflection() const;
125 
126     private:
127         const NamespaceResolver::Ptr m_nsResolver;
128     };
129 
130     template<typename TReportContext,
131              const ReportContext::ErrorCode InvalidQName,
132              const ReportContext::ErrorCode NoBinding>
expandQName(const QString & lexicalQName,const TReportContext & context,const NamespaceResolver::Ptr & nsResolver,const SourceLocationReflection * const r,const bool asForAttribute)133     QXmlName QNameConstructor::expandQName(const QString &lexicalQName,
134                                            const TReportContext &context,
135                                            const NamespaceResolver::Ptr &nsResolver,
136                                            const SourceLocationReflection *const r,
137                                            const bool asForAttribute)
138     {
139         Q_ASSERT(nsResolver);
140         Q_ASSERT(context);
141 
142         if(XPathHelper::isQName(lexicalQName))
143         {
144             QString prefix;
145             QString local;
146             XPathHelper::splitQName(lexicalQName, prefix, local);
147             const QXmlName::NamespaceCode nsCode = asForAttribute && prefix.isEmpty() ? QXmlName::NamespaceCode(StandardNamespaces::empty)
148                                                                                    : (nsResolver->lookupNamespaceURI(context->namePool()->allocatePrefix(prefix)));
149 
150             if(nsCode == NamespaceResolver::NoBinding)
151             {
152                 context->error(QtXmlPatterns::tr("No namespace binding exists for "
153                                   "the prefix %1 in %2").arg(formatKeyword(prefix),
154                                                              formatKeyword(lexicalQName)),
155                                NoBinding,
156                                r);
157                 return QXmlName(); /* Silence compiler warning. */
158             }
159             else
160                 return context->namePool()->allocateQName(context->namePool()->stringForNamespace(nsCode), local, prefix);
161         }
162         else
163         {
164             context->error(QtXmlPatterns::tr("%1 is an invalid %2")
165                               .arg(formatData(lexicalQName))
166                               .arg(formatType(context->namePool(), BuiltinTypes::xsQName)),
167                            InvalidQName,
168                            r);
169             return QXmlName(); /* Silence compiler warning. */
170         }
171     }
172 }
173 
174 QT_END_NAMESPACE
175 
176 #endif
177