1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #pragma once
24 
25 #include "../Container/Ptr.h"
26 #include "../Core/Variant.h"
27 #include "../Math/BoundingBox.h"
28 #include "../Math/Rect.h"
29 
30 namespace pugi
31 {
32 
33 struct xml_node_struct;
34 class xpath_node;
35 class xpath_node_set;
36 class xpath_query;
37 class xpath_variable_set;
38 
39 }
40 
41 namespace Urho3D
42 {
43 
44 class XMLFile;
45 class XPathQuery;
46 class XPathResultSet;
47 
48 /// Element in an XML file.
49 class URHO3D_API XMLElement
50 {
51 public:
52     /// Construct null element.
53     XMLElement();
54     /// Construct with document and node pointers.
55     XMLElement(XMLFile* file, pugi::xml_node_struct* node);
56     /// Construct from xpath query result set.
57     XMLElement(XMLFile* file, const XPathResultSet* resultSet, const pugi::xpath_node* xpathNode, unsigned xpathResultIndex);
58     /// Copy-construct from another element.
59     XMLElement(const XMLElement& rhs);
60     /// Destruct.
61     ~XMLElement();
62     /// Assignment operator.
63     XMLElement& operator =(const XMLElement& rhs);
64 
65     /// Create a child element.
66     XMLElement CreateChild(const String& name);
67     /// Create a child element.
68     XMLElement CreateChild(const char* name);
69     /// Return the first child element with name or create if does not exist.
70     XMLElement GetOrCreateChild(const String& name);
71     /// Return the first child element with name or create if does not exist.
72     XMLElement GetOrCreateChild(const char* name);
73     /// Remove a child element. Return true if successful.
74     bool RemoveChild(const XMLElement& element);
75     /// Remove a child element by name. Return true if successful.
76     bool RemoveChild(const String& name);
77     /// Remove a child element by name. Return true if successful.
78     bool RemoveChild(const char* name);
79     /// Remove child elements of certain name, or all child elements if name is empty. Return true if successful.
80     bool RemoveChildren(const String& name = String::EMPTY);
81     /// Remove child elements of certain name, or all child elements if name is empty. Return true if successful.
82     bool RemoveChildren(const char* name);
83     /// Remove an attribute by name. Return true if successful.
84     bool RemoveAttribute(const String& name = String::EMPTY);
85     /// Remove an attribute by name. Return true if successful.
86     bool RemoveAttribute(const char* name);
87 
88     /// Select an element/attribute using XPath query.
89     XMLElement SelectSingle(const String& query, pugi::xpath_variable_set* variables = 0) const;
90     /// Select an element/attribute using XPath query.
91     XMLElement SelectSinglePrepared(const XPathQuery& query) const;
92     /// Select elements/attributes using XPath query.
93     XPathResultSet Select(const String& query, pugi::xpath_variable_set* variables = 0) const;
94     /// Select elements/attributes using XPath query.
95     XPathResultSet SelectPrepared(const XPathQuery& query) const;
96 
97     /// Set the value for an inner node in the following format <node>value</node>.
98     bool SetValue(const String& value);
99     /// Set the value for an inner node in the following format <node>value</node>. Must be used on the <node> element.
100     bool SetValue(const char* value);
101     /// Set an attribute.
102     bool SetAttribute(const String& name, const String& value);
103     /// Set an attribute.
104     bool SetAttribute(const char* name, const char* value);
105     /// Set an attribute. Only valid if it is an attribute only XPath query result.
106     bool SetAttribute(const String& value);
107     /// Set an attribute. Only valid if it is an attribute only XPath query result.
108     bool SetAttribute(const char* value);
109     /// Set a bool attribute.
110     bool SetBool(const String& name, bool value);
111     /// Set a BoundingBox attribute.
112     bool SetBoundingBox(const BoundingBox& value);
113     /// Set a buffer attribute.
114     bool SetBuffer(const String& name, const void* data, unsigned size);
115     /// Set a buffer attribute.
116     bool SetBuffer(const String& name, const PODVector<unsigned char>& value);
117     /// Set a color attribute.
118     bool SetColor(const String& name, const Color& value);
119     /// Set a float attribute.
120     bool SetFloat(const String& name, float value);
121     /// Set a double attribute.
122     bool SetDouble(const String& name, double value);
123     /// Set an unsigned integer attribute.
124     bool SetUInt(const String& name, unsigned value);
125     /// Set an integer attribute.
126     bool SetInt(const String& name, int value);
127     /// Set an unsigned long long integer attribute.
128     bool SetUInt64(const String& name, unsigned long long value);
129     /// Set a long long integer attribute.
130     bool SetInt64(const String& name, long long value);
131     /// Set an IntRect attribute.
132     bool SetIntRect(const String& name, const IntRect& value);
133     /// Set an IntVector2 attribute.
134     bool SetIntVector2(const String& name, const IntVector2& value);
135     /// Set an IntVector3 attribute.
136     bool SetIntVector3(const String& name, const IntVector3& value);
137     /// Set a Rect attribute.
138     bool SetRect(const String& name, const Rect& value);
139     /// Set a quaternion attribute.
140     bool SetQuaternion(const String& name, const Quaternion& value);
141     /// Set a string attribute.
142     bool SetString(const String& name, const String& value);
143     /// Set a variant attribute.
144     bool SetVariant(const Variant& value);
145     /// Set a variant attribute excluding the type.
146     bool SetVariantValue(const Variant& value);
147     /// Set a resource reference attribute.
148     bool SetResourceRef(const ResourceRef& value);
149     /// Set a resource reference list attribute.
150     bool SetResourceRefList(const ResourceRefList& value);
151     /// Set a variant vector attribute. Creates child elements as necessary.
152     bool SetVariantVector(const VariantVector& value);
153     /// Set a string vector attribute. Creates child elements as necessary.
154     bool SetStringVector(const StringVector& value);
155     /// Set a variant map attribute. Creates child elements as necessary.
156     bool SetVariantMap(const VariantMap& value);
157     /// Set a Vector2 attribute.
158     bool SetVector2(const String& name, const Vector2& value);
159     /// Set a Vector3 attribute.
160     bool SetVector3(const String& name, const Vector3& value);
161     /// Set a Vector4 attribute.
162     bool SetVector4(const String& name, const Vector4& value);
163     /// Set a float, Vector or Matrix attribute stored in a variant.
164     bool SetVectorVariant(const String& name, const Variant& value);
165     /// Set a Matrix3 attribute.
166     bool SetMatrix3(const String& name, const Matrix3& value);
167     /// Set a Matrix3x4 attribute.
168     bool SetMatrix3x4(const String& name, const Matrix3x4& value);
169     /// Set a Matrix4 attribute.
170     bool SetMatrix4(const String& name, const Matrix4& value);
171 
172     /// Return whether does not refer to an element or an XPath node.
173     bool IsNull() const;
174     /// Return whether refers to an element or an XPath node.
175     bool NotNull() const;
176     /// Return true if refers to an element or an XPath node.
177     operator bool() const;
178     /// Return element name (or attribute name if it is an attribute only XPath query result).
179     String GetName() const;
180     /// Return whether has a child element.
181     bool HasChild(const String& name) const;
182     /// Return whether has a child element.
183     bool HasChild(const char* name) const;
184     /// Return child element, or null if missing.
185     XMLElement GetChild(const String& name = String::EMPTY) const;
186     /// Return child element, or null if missing.
187     XMLElement GetChild(const char* name) const;
188     /// Return next sibling element.
189     XMLElement GetNext(const String& name = String::EMPTY) const;
190     /// Return next sibling element.
191     XMLElement GetNext(const char* name) const;
192     /// Return parent element.
193     XMLElement GetParent() const;
194     /// Return number of attributes.
195     unsigned GetNumAttributes() const;
196     /// Return whether has an attribute.
197     bool HasAttribute(const String& name) const;
198     /// Return whether has an attribute.
199     bool HasAttribute(const char* name) const;
200     /// Return inner value, or empty if missing for nodes like <node>value</node>
201     String GetValue() const;
202     /// Return attribute, or empty if missing.
203     String GetAttribute(const String& name = String::EMPTY) const;
204     /// Return attribute, or empty if missing.
205     String GetAttribute(const char* name) const;
206     /// Return attribute as C string, or null if missing.
207     const char* GetAttributeCString(const char* name) const;
208     /// Return attribute in lowercase, or empty if missing.
209     String GetAttributeLower(const String& name) const;
210     /// Return attribute in lowercase, or empty if missing.
211     String GetAttributeLower(const char* name) const;
212     /// Return attribute in lowercase, or empty if missing.
213     String GetAttributeUpper(const String& name) const;
214     /// Return attribute in lowercase, or empty if missing.
215     String GetAttributeUpper(const char* name) const;
216     /// Return names of all attributes.
217     Vector<String> GetAttributeNames() const;
218     /// Return bool attribute, or false if missing.
219     bool GetBool(const String& name) const;
220     /// Return buffer attribute, or empty if missing.
221     PODVector<unsigned char> GetBuffer(const String& name) const;
222     /// Copy buffer attribute into a supplied buffer. Return true if buffer was large enough.
223     bool GetBuffer(const String& name, void* dest, unsigned size) const;
224     /// Return bounding box attribute, or empty if missing.
225     BoundingBox GetBoundingBox() const;
226     /// Return a color attribute, or default if missing.
227     Color GetColor(const String& name) const;
228     /// Return a float attribute, or zero if missing.
229     float GetFloat(const String& name) const;
230     /// Return a double attribute, or zero if missing.
231     double GetDouble(const String& name) const;
232     /// Return an unsigned integer attribute, or zero if missing.
233     unsigned GetUInt(const String& name) const;
234     /// Return an integer attribute, or zero if missing.
235     int GetInt(const String& name) const;
236     /// Return an unsigned long long integer attribute, or zero if missing.
237     unsigned long long GetUInt64(const String& name) const;
238     /// Return a long long integer attribute, or zero if missing.
239     long long GetInt64(const String& name) const;
240     /// Return an IntRect attribute, or default if missing.
241     IntRect GetIntRect(const String& name) const;
242     /// Return an IntVector2 attribute, or default if missing.
243     IntVector2 GetIntVector2(const String& name) const;
244     /// Return an IntVector3 attribute, or default if missing.
245     IntVector3 GetIntVector3(const String& name) const;
246     /// Return a Rect attribute, or default if missing.
247     Rect GetRect(const String& name) const;
248     /// Return a quaternion attribute, or default if missing.
249     Quaternion GetQuaternion(const String& name) const;
250     /// Return a variant attribute, or empty if missing.
251     Variant GetVariant() const;
252     /// Return a variant attribute with static type.
253     Variant GetVariantValue(VariantType type) const;
254     /// Return a resource reference attribute, or empty if missing.
255     ResourceRef GetResourceRef() const;
256     /// Return a resource reference list attribute, or empty if missing.
257     ResourceRefList GetResourceRefList() const;
258     /// Return a variant vector attribute, or empty if missing.
259     VariantVector GetVariantVector() const;
260     /// Return a string vector attribute, or empty if missing.
261     StringVector GetStringVector() const;
262     /// Return a variant map attribute, or empty if missing.
263     VariantMap GetVariantMap() const;
264     /// Return a Vector2 attribute, or zero vector if missing.
265     Vector2 GetVector2(const String& name) const;
266     /// Return a Vector3 attribute, or zero vector if missing.
267     Vector3 GetVector3(const String& name) const;
268     /// Return a Vector4 attribute, or zero vector if missing.
269     Vector4 GetVector4(const String& name) const;
270     /// Return any Vector attribute as Vector4. Missing coordinates will be zero.
271     Vector4 GetVector(const String& name) const;
272     /// Return a float, Vector or Matrix attribute as Variant.
273     Variant GetVectorVariant(const String& name) const;
274     /// Return a Matrix3 attribute, or zero matrix if missing.
275     Matrix3 GetMatrix3(const String& name) const;
276     /// Return a Matrix3x4 attribute, or zero matrix if missing.
277     Matrix3x4 GetMatrix3x4(const String& name) const;
278     /// Return a Matrix4 attribute, or zero matrix if missing.
279     Matrix4 GetMatrix4(const String& name) const;
280     /// Return XML file.
281     XMLFile* GetFile() const;
282 
283     /// Return pugixml xml_node_struct.
GetNode()284     pugi::xml_node_struct* GetNode() const { return node_; }
285 
286     /// Return XPath query result set.
GetXPathResultSet()287     const XPathResultSet* GetXPathResultSet() const { return xpathResultSet_; }
288 
289     /// Return pugixml xpath_node.
GetXPathNode()290     const pugi::xpath_node* GetXPathNode() const { return xpathNode_; }
291 
292     /// Return current result index.
GetXPathResultIndex()293     unsigned GetXPathResultIndex() const { return xpathResultIndex_; }
294 
295     /// Return next XPath query result. Only valid when this instance of XMLElement is itself one of the query result in the result set.
296     XMLElement NextResult() const;
297 
298     /// Empty XMLElement.
299     static const XMLElement EMPTY;
300 
301 private:
302     /// XML file.
303     WeakPtr<XMLFile> file_;
304     /// Pugixml node.
305     pugi::xml_node_struct* node_;
306     /// XPath query result set.
307     const XPathResultSet* xpathResultSet_;
308     /// Pugixml xpath_node.
309     const pugi::xpath_node* xpathNode_;
310     /// Current XPath query result index (used internally to advance to subsequent query result).
311     mutable unsigned xpathResultIndex_;
312 };
313 
314 /// XPath query result set.
315 class URHO3D_API XPathResultSet
316 {
317 public:
318     /// Construct empty result set.
319     XPathResultSet();
320     /// Construct with result set from XPath query.
321     XPathResultSet(XMLFile* file, pugi::xpath_node_set* resultSet);
322     /// Copy-construct.
323     XPathResultSet(const XPathResultSet& rhs);
324     /// Destruct.
325     ~XPathResultSet();
326     /// Assignment operator.
327     XPathResultSet& operator =(const XPathResultSet& rhs);
328     /// Return the n-th result in the set. Call XMLElement::GetNextResult() to get the subsequent result in the set.
329     /// Note: The XPathResultSet return value must be stored in a lhs variable to ensure the underlying xpath_node_set* is still valid while performing XPathResultSet::FirstResult(), XPathResultSet::operator [], and XMLElement::NextResult().
330     XMLElement operator [](unsigned index) const;
331     /// Return the first result in the set. Call XMLElement::GetNextResult() to get the subsequent result in the set.
332     /// Note: The XPathResultSet return value must be stored in a lhs variable to ensure the underlying xpath_node_set* is still valid while performing XPathResultSet::FirstResult(), XPathResultSet::operator [], and XMLElement::NextResult().
333     XMLElement FirstResult();
334     /// Return size of result set.
335     unsigned Size() const;
336     /// Return whether result set is empty.
337     bool Empty() const;
338 
339     /// Return pugixml xpath_node_set.
GetXPathNodeSet()340     pugi::xpath_node_set* GetXPathNodeSet() const { return resultSet_; }
341 
342 private:
343     /// XML file.
344     WeakPtr<XMLFile> file_;
345     /// Pugixml xpath_node_set.
346     pugi::xpath_node_set* resultSet_;
347 };
348 
349 /// XPath query.
350 class URHO3D_API XPathQuery
351 {
352 public:
353     /// Construct empty.
354     XPathQuery();
355     /// Construct XPath query object with query string and variable string. The variable string format is "name1:type1,name2:type2,..." where type is one of "Bool", "Float", "String", "ResultSet".
356     XPathQuery(const String& queryString, const String& variableString = String::EMPTY);
357     /// Destruct.
358     ~XPathQuery();
359     /// Bind query object with variable set.
360     void Bind();
361     /// Add/Set a bool variable. Return true if successful.
362     bool SetVariable(const String& name, bool value);
363     /// Add/Set a float variable. Return true if successful.
364     bool SetVariable(const String& name, float value);
365     /// Add/Set a string variable. Return true if successful.
366     bool SetVariable(const String& name, const String& value);
367     /// Add/Set a string variable. Return true if successful.
368     bool SetVariable(const char* name, const char* value);
369     /// Add/Set an XPath query result set variable. Return true if successful.
370     bool SetVariable(const String& name, const XPathResultSet& value);
371     /// Set XPath query string and variable string. The variable string format is "name1:type1,name2:type2,..." where type is one of "Bool", "Float", "String", "ResultSet".
372     bool SetQuery(const String& queryString, const String& variableString = String::EMPTY, bool bind = true);
373     /// Clear by removing all variables and XPath query object.
374     void Clear();
375     /// Evaluate XPath query and expecting a boolean return value.
376     bool EvaluateToBool(XMLElement element) const;
377     /// Evaluate XPath query and expecting a float return value.
378     float EvaluateToFloat(XMLElement element) const;
379     /// Evaluate XPath query and expecting a string return value.
380     String EvaluateToString(XMLElement element) const;
381     /// Evaluate XPath query and expecting an XPath query result set as return value.
382     /// Note: The XPathResultSet return value must be stored in a lhs variable to ensure the underlying xpath_node_set* is still valid while performing XPathResultSet::FirstResult(), XPathResultSet::operator [], and XMLElement::NextResult().
383     XPathResultSet Evaluate(XMLElement element) const;
384 
385     /// Return query string.
GetQuery()386     String GetQuery() const { return queryString_; }
387 
388     /// Return pugixml xpath_query.
GetXPathQuery()389     pugi::xpath_query* GetXPathQuery() const { return query_.Get(); }
390 
391     /// Return pugixml xpath_variable_set.
GetXPathVariableSet()392     pugi::xpath_variable_set* GetXPathVariableSet() const { return variables_.Get(); }
393 
394 private:
395     /// XPath query string.
396     String queryString_;
397     /// Pugixml xpath_query.
398     UniquePtr<pugi::xpath_query> query_;
399     /// Pugixml xpath_variable_set.
400     UniquePtr<pugi::xpath_variable_set> variables_;
401 };
402 
403 }
404