XMLElement.cpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204
  1. //
  2. // Copyright (c) 2008-2020 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. #include "../Precompiled.h"
  23. #include "../Core/Context.h"
  24. #include "../IO/Log.h"
  25. #include "../Resource/XMLFile.h"
  26. #include <PugiXml/pugixml.hpp>
  27. #include "../DebugNew.h"
  28. namespace Urho3D
  29. {
  30. const XMLElement XMLElement::EMPTY;
  31. XMLElement::XMLElement() :
  32. node_(nullptr),
  33. xpathResultSet_(nullptr),
  34. xpathNode_(nullptr),
  35. xpathResultIndex_(0)
  36. {
  37. }
  38. XMLElement::XMLElement(XMLFile* file, pugi::xml_node_struct* node) :
  39. file_(file),
  40. node_(node),
  41. xpathResultSet_(nullptr),
  42. xpathNode_(nullptr),
  43. xpathResultIndex_(0)
  44. {
  45. }
  46. XMLElement::XMLElement(XMLFile* file, const XPathResultSet* resultSet, const pugi::xpath_node* xpathNode,
  47. unsigned xpathResultIndex) :
  48. file_(file),
  49. node_(nullptr),
  50. xpathResultSet_(resultSet),
  51. xpathNode_(resultSet ? xpathNode : (xpathNode ? new pugi::xpath_node(*xpathNode) : nullptr)),
  52. xpathResultIndex_(xpathResultIndex)
  53. {
  54. }
  55. XMLElement::XMLElement(const XMLElement& rhs) :
  56. file_(rhs.file_),
  57. node_(rhs.node_),
  58. xpathResultSet_(rhs.xpathResultSet_),
  59. xpathNode_(rhs.xpathResultSet_ ? rhs.xpathNode_ : (rhs.xpathNode_ ? new pugi::xpath_node(*rhs.xpathNode_) : nullptr)),
  60. xpathResultIndex_(rhs.xpathResultIndex_)
  61. {
  62. }
  63. XMLElement::~XMLElement()
  64. {
  65. // XMLElement class takes the ownership of a single xpath_node object, so destruct it now
  66. if (!xpathResultSet_ && xpathNode_)
  67. {
  68. delete xpathNode_;
  69. xpathNode_ = nullptr;
  70. }
  71. }
  72. XMLElement& XMLElement::operator =(const XMLElement& rhs)
  73. {
  74. file_ = rhs.file_;
  75. node_ = rhs.node_;
  76. xpathResultSet_ = rhs.xpathResultSet_;
  77. xpathNode_ = rhs.xpathResultSet_ ? rhs.xpathNode_ : (rhs.xpathNode_ ? new pugi::xpath_node(*rhs.xpathNode_) : nullptr);
  78. xpathResultIndex_ = rhs.xpathResultIndex_;
  79. return *this;
  80. }
  81. XMLElement XMLElement::CreateChild(const String& name)
  82. {
  83. return CreateChild(name.CString());
  84. }
  85. XMLElement XMLElement::CreateChild(const char* name)
  86. {
  87. if (!file_ || (!node_ && !xpathNode_))
  88. return XMLElement();
  89. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  90. pugi::xml_node child = const_cast<pugi::xml_node&>(node).append_child(name);
  91. return XMLElement(file_, child.internal_object());
  92. }
  93. XMLElement XMLElement::GetOrCreateChild(const String& name)
  94. {
  95. XMLElement child = GetChild(name);
  96. if (child.NotNull())
  97. return child;
  98. else
  99. return CreateChild(name);
  100. }
  101. XMLElement XMLElement::GetOrCreateChild(const char* name)
  102. {
  103. XMLElement child = GetChild(name);
  104. if (child.NotNull())
  105. return child;
  106. else
  107. return CreateChild(name);
  108. }
  109. bool XMLElement::AppendChild(XMLElement element, bool asCopy)
  110. {
  111. if (!element.file_ || (!element.node_ && !element.xpathNode_) || !file_ || (!node_ && !xpathNode_))
  112. return false;
  113. pugi::xml_node node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  114. const pugi::xml_node& child = element.xpathNode_ ? element.xpathNode_->node() : pugi::xml_node(element.node_);
  115. if (asCopy)
  116. node.append_copy(child);
  117. else
  118. node.append_move(child);
  119. return true;
  120. }
  121. bool XMLElement::Remove()
  122. {
  123. return GetParent().RemoveChild(*this);
  124. }
  125. bool XMLElement::RemoveChild(const XMLElement& element)
  126. {
  127. if (!element.file_ || (!element.node_ && !element.xpathNode_) || !file_ || (!node_ && !xpathNode_))
  128. return false;
  129. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  130. const pugi::xml_node& child = element.xpathNode_ ? element.xpathNode_->node() : pugi::xml_node(element.node_);
  131. return const_cast<pugi::xml_node&>(node).remove_child(child);
  132. }
  133. bool XMLElement::RemoveChild(const String& name)
  134. {
  135. return RemoveChild(name.CString());
  136. }
  137. bool XMLElement::RemoveChild(const char* name)
  138. {
  139. if (!file_ || (!node_ && !xpathNode_))
  140. return false;
  141. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  142. return const_cast<pugi::xml_node&>(node).remove_child(name);
  143. }
  144. bool XMLElement::RemoveChildren(const String& name)
  145. {
  146. return RemoveChildren(name.CString());
  147. }
  148. bool XMLElement::RemoveChildren(const char* name)
  149. {
  150. if ((!file_ || !node_) && !xpathNode_)
  151. return false;
  152. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  153. if (!String::CStringLength(name))
  154. {
  155. for (;;)
  156. {
  157. pugi::xml_node child = node.last_child();
  158. if (child.empty())
  159. break;
  160. const_cast<pugi::xml_node&>(node).remove_child(child);
  161. }
  162. }
  163. else
  164. {
  165. for (;;)
  166. {
  167. pugi::xml_node child = node.child(name);
  168. if (child.empty())
  169. break;
  170. const_cast<pugi::xml_node&>(node).remove_child(child);
  171. }
  172. }
  173. return true;
  174. }
  175. bool XMLElement::RemoveAttribute(const String& name)
  176. {
  177. return RemoveAttribute(name.CString());
  178. }
  179. bool XMLElement::RemoveAttribute(const char* name)
  180. {
  181. if (!file_ || (!node_ && !xpathNode_))
  182. return false;
  183. // If xpath_node contains just attribute, remove it regardless of the specified name
  184. if (xpathNode_ && xpathNode_->attribute())
  185. return xpathNode_->parent().remove_attribute(
  186. xpathNode_->attribute()); // In attribute context, xpath_node's parent is the parent node of the attribute itself
  187. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  188. return const_cast<pugi::xml_node&>(node).remove_attribute(node.attribute(name));
  189. }
  190. XMLElement XMLElement::SelectSingle(const String& query, pugi::xpath_variable_set* variables) const
  191. {
  192. if (!file_ || (!node_ && !xpathNode_))
  193. return XMLElement();
  194. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  195. pugi::xpath_node result = node.select_single_node(query.CString(), variables);
  196. return XMLElement(file_, nullptr, &result, 0);
  197. }
  198. XMLElement XMLElement::SelectSinglePrepared(const XPathQuery& query) const
  199. {
  200. if (!file_ || (!node_ && !xpathNode_ && !query.GetXPathQuery()))
  201. return XMLElement();
  202. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  203. pugi::xpath_node result = node.select_single_node(*query.GetXPathQuery());
  204. return XMLElement(file_, nullptr, &result, 0);
  205. }
  206. XPathResultSet XMLElement::Select(const String& query, pugi::xpath_variable_set* variables) const
  207. {
  208. if (!file_ || (!node_ && !xpathNode_))
  209. return XPathResultSet();
  210. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  211. pugi::xpath_node_set result = node.select_nodes(query.CString(), variables);
  212. return XPathResultSet(file_, &result);
  213. }
  214. XPathResultSet XMLElement::SelectPrepared(const XPathQuery& query) const
  215. {
  216. if (!file_ || (!node_ && !xpathNode_ && query.GetXPathQuery()))
  217. return XPathResultSet();
  218. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  219. pugi::xpath_node_set result = node.select_nodes(*query.GetXPathQuery());
  220. return XPathResultSet(file_, &result);
  221. }
  222. bool XMLElement::SetValue(const String& value)
  223. {
  224. return SetValue(value.CString());
  225. }
  226. bool XMLElement::SetValue(const char* value)
  227. {
  228. if (!file_ || (!node_ && !xpathNode_))
  229. return false;
  230. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  231. // Search for existing value first
  232. for (pugi::xml_node child = node.first_child(); child; child = child.next_sibling())
  233. {
  234. if (child.type() == pugi::node_pcdata)
  235. return const_cast<pugi::xml_node&>(child).set_value(value);
  236. }
  237. // If no previous value found, append new
  238. return const_cast<pugi::xml_node&>(node).append_child(pugi::node_pcdata).set_value(value);
  239. }
  240. bool XMLElement::SetAttribute(const String& name, const String& value)
  241. {
  242. return SetAttribute(name.CString(), value.CString());
  243. }
  244. bool XMLElement::SetAttribute(const char* name, const char* value)
  245. {
  246. if (!file_ || (!node_ && !xpathNode_))
  247. return false;
  248. // If xpath_node contains just attribute, set its value regardless of the specified name
  249. if (xpathNode_ && xpathNode_->attribute())
  250. return xpathNode_->attribute().set_value(value);
  251. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  252. pugi::xml_attribute attr = node.attribute(name);
  253. if (attr.empty())
  254. attr = const_cast<pugi::xml_node&>(node).append_attribute(name);
  255. return attr.set_value(value);
  256. }
  257. bool XMLElement::SetAttribute(const String& value)
  258. {
  259. return SetAttribute(value.CString());
  260. }
  261. bool XMLElement::SetAttribute(const char* value)
  262. {
  263. // If xpath_node contains just attribute, set its value
  264. return xpathNode_ && xpathNode_->attribute() && xpathNode_->attribute().set_value(value);
  265. }
  266. bool XMLElement::SetBool(const String& name, bool value)
  267. {
  268. return SetAttribute(name, String(value));
  269. }
  270. bool XMLElement::SetBoundingBox(const BoundingBox& value)
  271. {
  272. if (!SetVector3("min", value.min_))
  273. return false;
  274. return SetVector3("max", value.max_);
  275. }
  276. bool XMLElement::SetBuffer(const String& name, const void* data, unsigned size)
  277. {
  278. String dataStr;
  279. BufferToString(dataStr, data, size);
  280. return SetAttribute(name, dataStr);
  281. }
  282. bool XMLElement::SetBuffer(const String& name, const PODVector<unsigned char>& value)
  283. {
  284. if (!value.Size())
  285. return SetAttribute(name, String::EMPTY);
  286. else
  287. return SetBuffer(name, &value[0], value.Size());
  288. }
  289. bool XMLElement::SetColor(const String& name, const Color& value)
  290. {
  291. return SetAttribute(name, value.ToString());
  292. }
  293. bool XMLElement::SetFloat(const String& name, float value)
  294. {
  295. return SetAttribute(name, String(value));
  296. }
  297. bool XMLElement::SetDouble(const String& name, double value)
  298. {
  299. return SetAttribute(name, String(value));
  300. }
  301. bool XMLElement::SetUInt(const String& name, unsigned value)
  302. {
  303. return SetAttribute(name, String(value));
  304. }
  305. bool XMLElement::SetInt(const String& name, int value)
  306. {
  307. return SetAttribute(name, String(value));
  308. }
  309. bool XMLElement::SetUInt64(const String& name, unsigned long long value)
  310. {
  311. return SetAttribute(name, String(value));
  312. }
  313. bool XMLElement::SetInt64(const String& name, long long value)
  314. {
  315. return SetAttribute(name, String(value));
  316. }
  317. bool XMLElement::SetIntRect(const String& name, const IntRect& value)
  318. {
  319. return SetAttribute(name, value.ToString());
  320. }
  321. bool XMLElement::SetIntVector2(const String& name, const IntVector2& value)
  322. {
  323. return SetAttribute(name, value.ToString());
  324. }
  325. bool XMLElement::SetIntVector3(const String& name, const IntVector3& value)
  326. {
  327. return SetAttribute(name, value.ToString());
  328. }
  329. bool XMLElement::SetRect(const String& name, const Rect& value)
  330. {
  331. return SetAttribute(name, value.ToString());
  332. }
  333. bool XMLElement::SetQuaternion(const String& name, const Quaternion& value)
  334. {
  335. return SetAttribute(name, value.ToString());
  336. }
  337. bool XMLElement::SetString(const String& name, const String& value)
  338. {
  339. return SetAttribute(name, value);
  340. }
  341. bool XMLElement::SetVariant(const Variant& value)
  342. {
  343. if (!SetAttribute("type", value.GetTypeName()))
  344. return false;
  345. return SetVariantValue(value);
  346. }
  347. bool XMLElement::SetVariantValue(const Variant& value)
  348. {
  349. switch (value.GetType())
  350. {
  351. case VAR_RESOURCEREF:
  352. return SetResourceRef(value.GetResourceRef());
  353. case VAR_RESOURCEREFLIST:
  354. return SetResourceRefList(value.GetResourceRefList());
  355. case VAR_VARIANTVECTOR:
  356. return SetVariantVector(value.GetVariantVector());
  357. case VAR_STRINGVECTOR:
  358. return SetStringVector(value.GetStringVector());
  359. case VAR_VARIANTMAP:
  360. return SetVariantMap(value.GetVariantMap());
  361. default:
  362. return SetAttribute("value", value.ToString().CString());
  363. }
  364. }
  365. bool XMLElement::SetResourceRef(const ResourceRef& value)
  366. {
  367. if (!file_ || (!node_ && !xpathNode_))
  368. return false;
  369. // Need the context to query for the type
  370. Context* context = file_->GetContext();
  371. return SetAttribute("value", String(context->GetTypeName(value.type_)) + ";" + value.name_);
  372. }
  373. bool XMLElement::SetResourceRefList(const ResourceRefList& value)
  374. {
  375. if (!file_ || (!node_ && !xpathNode_))
  376. return false;
  377. // Need the context to query for the type
  378. Context* context = file_->GetContext();
  379. String str(context->GetTypeName(value.type_));
  380. for (unsigned i = 0; i < value.names_.Size(); ++i)
  381. {
  382. str += ";";
  383. str += value.names_[i];
  384. }
  385. return SetAttribute("value", str.CString());
  386. }
  387. bool XMLElement::SetVariantVector(const VariantVector& value)
  388. {
  389. // Must remove all existing variant child elements (if they exist) to not cause confusion
  390. if (!RemoveChildren("variant"))
  391. return false;
  392. for (VariantVector::ConstIterator i = value.Begin(); i != value.End(); ++i)
  393. {
  394. XMLElement variantElem = CreateChild("variant");
  395. if (!variantElem)
  396. return false;
  397. variantElem.SetVariant(*i);
  398. }
  399. return true;
  400. }
  401. bool XMLElement::SetStringVector(const StringVector& value)
  402. {
  403. if (!RemoveChildren("string"))
  404. return false;
  405. for (StringVector::ConstIterator i = value.Begin(); i != value.End(); ++i)
  406. {
  407. XMLElement stringElem = CreateChild("string");
  408. if (!stringElem)
  409. return false;
  410. stringElem.SetAttribute("value", *i);
  411. }
  412. return true;
  413. }
  414. bool XMLElement::SetVariantMap(const VariantMap& value)
  415. {
  416. if (!RemoveChildren("variant"))
  417. return false;
  418. for (VariantMap::ConstIterator i = value.Begin(); i != value.End(); ++i)
  419. {
  420. XMLElement variantElem = CreateChild("variant");
  421. if (!variantElem)
  422. return false;
  423. variantElem.SetUInt("hash", i->first_.Value());
  424. variantElem.SetVariant(i->second_);
  425. }
  426. return true;
  427. }
  428. bool XMLElement::SetVector2(const String& name, const Vector2& value)
  429. {
  430. return SetAttribute(name, value.ToString());
  431. }
  432. bool XMLElement::SetVector3(const String& name, const Vector3& value)
  433. {
  434. return SetAttribute(name, value.ToString());
  435. }
  436. bool XMLElement::SetVector4(const String& name, const Vector4& value)
  437. {
  438. return SetAttribute(name, value.ToString());
  439. }
  440. bool XMLElement::SetVectorVariant(const String& name, const Variant& value)
  441. {
  442. VariantType type = value.GetType();
  443. if (type == VAR_FLOAT || type == VAR_VECTOR2 || type == VAR_VECTOR3 || type == VAR_VECTOR4 || type == VAR_MATRIX3 ||
  444. type == VAR_MATRIX3X4 || type == VAR_MATRIX4)
  445. return SetAttribute(name, value.ToString());
  446. else
  447. return false;
  448. }
  449. bool XMLElement::SetMatrix3(const String& name, const Matrix3& value)
  450. {
  451. return SetAttribute(name, value.ToString());
  452. }
  453. bool XMLElement::SetMatrix3x4(const String& name, const Matrix3x4& value)
  454. {
  455. return SetAttribute(name, value.ToString());
  456. }
  457. bool XMLElement::SetMatrix4(const String& name, const Matrix4& value)
  458. {
  459. return SetAttribute(name, value.ToString());
  460. }
  461. bool XMLElement::IsNull() const
  462. {
  463. return !NotNull();
  464. }
  465. bool XMLElement::NotNull() const
  466. {
  467. return node_ || (xpathNode_ && !xpathNode_->operator !());
  468. }
  469. XMLElement::operator bool() const
  470. {
  471. return NotNull();
  472. }
  473. String XMLElement::GetName() const
  474. {
  475. if ((!file_ || !node_) && !xpathNode_)
  476. return String();
  477. // If xpath_node contains just attribute, return its name instead
  478. if (xpathNode_ && xpathNode_->attribute())
  479. return String(xpathNode_->attribute().name());
  480. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  481. return String(node.name());
  482. }
  483. bool XMLElement::HasChild(const String& name) const
  484. {
  485. return HasChild(name.CString());
  486. }
  487. bool XMLElement::HasChild(const char* name) const
  488. {
  489. if (!file_ || (!node_ && !xpathNode_))
  490. return false;
  491. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  492. return !node.child(name).empty();
  493. }
  494. XMLElement XMLElement::GetChild(const String& name) const
  495. {
  496. return GetChild(name.CString());
  497. }
  498. XMLElement XMLElement::GetChild(const char* name) const
  499. {
  500. if (!file_ || (!node_ && !xpathNode_))
  501. return XMLElement();
  502. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  503. if (!String::CStringLength(name))
  504. return XMLElement(file_, node.first_child().internal_object());
  505. else
  506. return XMLElement(file_, node.child(name).internal_object());
  507. }
  508. XMLElement XMLElement::GetNext(const String& name) const
  509. {
  510. return GetNext(name.CString());
  511. }
  512. XMLElement XMLElement::GetNext(const char* name) const
  513. {
  514. if (!file_ || (!node_ && !xpathNode_))
  515. return XMLElement();
  516. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  517. if (!String::CStringLength(name))
  518. return XMLElement(file_, node.next_sibling().internal_object());
  519. else
  520. return XMLElement(file_, node.next_sibling(name).internal_object());
  521. }
  522. XMLElement XMLElement::GetParent() const
  523. {
  524. if (!file_ || (!node_ && !xpathNode_))
  525. return XMLElement();
  526. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  527. return XMLElement(file_, node.parent().internal_object());
  528. }
  529. unsigned XMLElement::GetNumAttributes() const
  530. {
  531. if (!file_ || (!node_ && !xpathNode_))
  532. return 0;
  533. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  534. unsigned ret = 0;
  535. pugi::xml_attribute attr = node.first_attribute();
  536. while (!attr.empty())
  537. {
  538. ++ret;
  539. attr = attr.next_attribute();
  540. }
  541. return ret;
  542. }
  543. bool XMLElement::HasAttribute(const String& name) const
  544. {
  545. return HasAttribute(name.CString());
  546. }
  547. bool XMLElement::HasAttribute(const char* name) const
  548. {
  549. if (!file_ || (!node_ && !xpathNode_))
  550. return false;
  551. // If xpath_node contains just attribute, check against it
  552. if (xpathNode_ && xpathNode_->attribute())
  553. return String(xpathNode_->attribute().name()) == name;
  554. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  555. return !node.attribute(name).empty();
  556. }
  557. String XMLElement::GetValue() const
  558. {
  559. if (!file_ || (!node_ && !xpathNode_))
  560. return String::EMPTY;
  561. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  562. return String(node.child_value());
  563. }
  564. String XMLElement::GetAttribute(const String& name) const
  565. {
  566. return String(GetAttributeCString(name.CString()));
  567. }
  568. String XMLElement::GetAttribute(const char* name) const
  569. {
  570. return String(GetAttributeCString(name));
  571. }
  572. const char* XMLElement::GetAttributeCString(const char* name) const
  573. {
  574. if (!file_ || (!node_ && !xpathNode_))
  575. return nullptr;
  576. // If xpath_node contains just attribute, return it regardless of the specified name
  577. if (xpathNode_ && xpathNode_->attribute())
  578. return xpathNode_->attribute().value();
  579. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  580. return node.attribute(name).value();
  581. }
  582. String XMLElement::GetAttributeLower(const String& name) const
  583. {
  584. return GetAttribute(name).ToLower();
  585. }
  586. String XMLElement::GetAttributeLower(const char* name) const
  587. {
  588. return String(GetAttribute(name)).ToLower();
  589. }
  590. String XMLElement::GetAttributeUpper(const String& name) const
  591. {
  592. return GetAttribute(name).ToUpper();
  593. }
  594. String XMLElement::GetAttributeUpper(const char* name) const
  595. {
  596. return String(GetAttribute(name)).ToUpper();
  597. }
  598. Vector<String> XMLElement::GetAttributeNames() const
  599. {
  600. if (!file_ || (!node_ && !xpathNode_))
  601. return Vector<String>();
  602. const pugi::xml_node& node = xpathNode_ ? xpathNode_->node() : pugi::xml_node(node_);
  603. Vector<String> ret;
  604. pugi::xml_attribute attr = node.first_attribute();
  605. while (!attr.empty())
  606. {
  607. ret.Push(String(attr.name()));
  608. attr = attr.next_attribute();
  609. }
  610. return ret;
  611. }
  612. bool XMLElement::GetBool(const String& name) const
  613. {
  614. return ToBool(GetAttribute(name));
  615. }
  616. BoundingBox XMLElement::GetBoundingBox() const
  617. {
  618. BoundingBox ret;
  619. ret.min_ = GetVector3("min");
  620. ret.max_ = GetVector3("max");
  621. return ret;
  622. }
  623. PODVector<unsigned char> XMLElement::GetBuffer(const String& name) const
  624. {
  625. PODVector<unsigned char> ret;
  626. StringToBuffer(ret, GetAttribute(name));
  627. return ret;
  628. }
  629. bool XMLElement::GetBuffer(const String& name, void* dest, unsigned size) const
  630. {
  631. Vector<String> bytes = GetAttribute(name).Split(' ');
  632. if (size < bytes.Size())
  633. return false;
  634. auto* destBytes = (unsigned char*)dest;
  635. for (unsigned i = 0; i < bytes.Size(); ++i)
  636. destBytes[i] = (unsigned char)ToInt(bytes[i]);
  637. return true;
  638. }
  639. Color XMLElement::GetColor(const String& name) const
  640. {
  641. return ToColor(GetAttribute(name));
  642. }
  643. float XMLElement::GetFloat(const String& name) const
  644. {
  645. return ToFloat(GetAttribute(name));
  646. }
  647. double XMLElement::GetDouble(const String& name) const
  648. {
  649. return ToDouble(GetAttribute(name));
  650. }
  651. unsigned XMLElement::GetUInt(const String& name) const
  652. {
  653. return ToUInt(GetAttribute(name));
  654. }
  655. int XMLElement::GetInt(const String& name) const
  656. {
  657. return ToInt(GetAttribute(name));
  658. }
  659. unsigned long long XMLElement::GetUInt64(const String& name) const
  660. {
  661. return ToUInt64(GetAttribute(name));
  662. }
  663. long long XMLElement::GetInt64(const String& name) const
  664. {
  665. return ToInt64(GetAttribute(name));
  666. }
  667. IntRect XMLElement::GetIntRect(const String& name) const
  668. {
  669. return ToIntRect(GetAttribute(name));
  670. }
  671. IntVector2 XMLElement::GetIntVector2(const String& name) const
  672. {
  673. return ToIntVector2(GetAttribute(name));
  674. }
  675. IntVector3 XMLElement::GetIntVector3(const String& name) const
  676. {
  677. return ToIntVector3(GetAttribute(name));
  678. }
  679. Quaternion XMLElement::GetQuaternion(const String& name) const
  680. {
  681. return ToQuaternion(GetAttribute(name));
  682. }
  683. Rect XMLElement::GetRect(const String& name) const
  684. {
  685. return ToRect(GetAttribute(name));
  686. }
  687. Variant XMLElement::GetVariant() const
  688. {
  689. VariantType type = Variant::GetTypeFromName(GetAttribute("type"));
  690. return GetVariantValue(type);
  691. }
  692. Variant XMLElement::GetVariantValue(VariantType type) const
  693. {
  694. Variant ret;
  695. if (type == VAR_RESOURCEREF)
  696. ret = GetResourceRef();
  697. else if (type == VAR_RESOURCEREFLIST)
  698. ret = GetResourceRefList();
  699. else if (type == VAR_VARIANTVECTOR)
  700. ret = GetVariantVector();
  701. else if (type == VAR_STRINGVECTOR)
  702. ret = GetStringVector();
  703. else if (type == VAR_VARIANTMAP)
  704. ret = GetVariantMap();
  705. else
  706. ret.FromString(type, GetAttributeCString("value"));
  707. return ret;
  708. }
  709. ResourceRef XMLElement::GetResourceRef() const
  710. {
  711. ResourceRef ret;
  712. Vector<String> values = GetAttribute("value").Split(';');
  713. if (values.Size() == 2)
  714. {
  715. ret.type_ = values[0];
  716. ret.name_ = values[1];
  717. }
  718. return ret;
  719. }
  720. ResourceRefList XMLElement::GetResourceRefList() const
  721. {
  722. ResourceRefList ret;
  723. Vector<String> values = GetAttribute("value").Split(';', true);
  724. if (values.Size() >= 1)
  725. {
  726. ret.type_ = values[0];
  727. ret.names_.Resize(values.Size() - 1);
  728. for (unsigned i = 1; i < values.Size(); ++i)
  729. ret.names_[i - 1] = values[i];
  730. }
  731. return ret;
  732. }
  733. VariantVector XMLElement::GetVariantVector() const
  734. {
  735. VariantVector ret;
  736. XMLElement variantElem = GetChild("variant");
  737. while (variantElem)
  738. {
  739. ret.Push(variantElem.GetVariant());
  740. variantElem = variantElem.GetNext("variant");
  741. }
  742. return ret;
  743. }
  744. StringVector XMLElement::GetStringVector() const
  745. {
  746. StringVector ret;
  747. XMLElement stringElem = GetChild("string");
  748. while (stringElem)
  749. {
  750. ret.Push(stringElem.GetAttributeCString("value"));
  751. stringElem = stringElem.GetNext("string");
  752. }
  753. return ret;
  754. }
  755. VariantMap XMLElement::GetVariantMap() const
  756. {
  757. VariantMap ret;
  758. XMLElement variantElem = GetChild("variant");
  759. while (variantElem)
  760. {
  761. // If this is a manually edited map, user can not be expected to calculate hashes manually. Also accept "name" attribute
  762. if (variantElem.HasAttribute("name"))
  763. ret[StringHash(variantElem.GetAttribute("name"))] = variantElem.GetVariant();
  764. else if (variantElem.HasAttribute("hash"))
  765. ret[StringHash(variantElem.GetUInt("hash"))] = variantElem.GetVariant();
  766. variantElem = variantElem.GetNext("variant");
  767. }
  768. return ret;
  769. }
  770. Vector2 XMLElement::GetVector2(const String& name) const
  771. {
  772. return ToVector2(GetAttribute(name));
  773. }
  774. Vector3 XMLElement::GetVector3(const String& name) const
  775. {
  776. return ToVector3(GetAttribute(name));
  777. }
  778. Vector4 XMLElement::GetVector4(const String& name) const
  779. {
  780. return ToVector4(GetAttribute(name));
  781. }
  782. Vector4 XMLElement::GetVector(const String& name) const
  783. {
  784. return ToVector4(GetAttribute(name), true);
  785. }
  786. Variant XMLElement::GetVectorVariant(const String& name) const
  787. {
  788. return ToVectorVariant(GetAttribute(name));
  789. }
  790. Matrix3 XMLElement::GetMatrix3(const String& name) const
  791. {
  792. return ToMatrix3(GetAttribute(name));
  793. }
  794. Matrix3x4 XMLElement::GetMatrix3x4(const String& name) const
  795. {
  796. return ToMatrix3x4(GetAttribute(name));
  797. }
  798. Matrix4 XMLElement::GetMatrix4(const String& name) const
  799. {
  800. return ToMatrix4(GetAttribute(name));
  801. }
  802. XMLFile* XMLElement::GetFile() const
  803. {
  804. return file_;
  805. }
  806. XMLElement XMLElement::NextResult() const
  807. {
  808. if (!xpathResultSet_ || !xpathNode_)
  809. return XMLElement();
  810. return xpathResultSet_->operator [](++xpathResultIndex_);
  811. }
  812. XPathResultSet::XPathResultSet() :
  813. resultSet_(nullptr)
  814. {
  815. }
  816. XPathResultSet::XPathResultSet(XMLFile* file, pugi::xpath_node_set* resultSet) :
  817. file_(file),
  818. resultSet_(resultSet ? new pugi::xpath_node_set(resultSet->begin(), resultSet->end()) : nullptr)
  819. {
  820. // Sort the node set in forward document order
  821. if (resultSet_)
  822. resultSet_->sort();
  823. }
  824. XPathResultSet::XPathResultSet(const XPathResultSet& rhs) :
  825. file_(rhs.file_),
  826. resultSet_(rhs.resultSet_ ? new pugi::xpath_node_set(rhs.resultSet_->begin(), rhs.resultSet_->end()) : nullptr)
  827. {
  828. }
  829. XPathResultSet::~XPathResultSet()
  830. {
  831. delete resultSet_;
  832. resultSet_ = nullptr;
  833. }
  834. XPathResultSet& XPathResultSet::operator =(const XPathResultSet& rhs)
  835. {
  836. file_ = rhs.file_;
  837. resultSet_ = rhs.resultSet_ ? new pugi::xpath_node_set(rhs.resultSet_->begin(), rhs.resultSet_->end()) : nullptr;
  838. return *this;
  839. }
  840. XMLElement XPathResultSet::operator [](unsigned index) const
  841. {
  842. if (!resultSet_)
  843. URHO3D_LOGERRORF(
  844. "Could not return result at index: %u. Most probably this is caused by the XPathResultSet not being stored in a lhs variable.",
  845. index);
  846. return resultSet_ && index < Size() ? XMLElement(file_, this, &resultSet_->operator [](index), index) : XMLElement();
  847. }
  848. XMLElement XPathResultSet::FirstResult()
  849. {
  850. return operator [](0);
  851. }
  852. unsigned XPathResultSet::Size() const
  853. {
  854. return resultSet_ ? (unsigned)resultSet_->size() : 0;
  855. }
  856. bool XPathResultSet::Empty() const
  857. {
  858. return resultSet_ ? resultSet_->empty() : true;
  859. }
  860. XPathQuery::XPathQuery() = default;
  861. XPathQuery::XPathQuery(const String& queryString, const String& variableString)
  862. {
  863. SetQuery(queryString, variableString);
  864. }
  865. XPathQuery::~XPathQuery() = default;
  866. void XPathQuery::Bind()
  867. {
  868. // Delete previous query object and create a new one binding it with variable set
  869. query_ = new pugi::xpath_query(queryString_.CString(), variables_.Get());
  870. }
  871. bool XPathQuery::SetVariable(const String& name, bool value)
  872. {
  873. if (!variables_)
  874. variables_ = new pugi::xpath_variable_set();
  875. return variables_->set(name.CString(), value);
  876. }
  877. bool XPathQuery::SetVariable(const String& name, float value)
  878. {
  879. if (!variables_)
  880. variables_ = new pugi::xpath_variable_set();
  881. return variables_->set(name.CString(), value);
  882. }
  883. bool XPathQuery::SetVariable(const String& name, const String& value)
  884. {
  885. return SetVariable(name.CString(), value.CString());
  886. }
  887. bool XPathQuery::SetVariable(const char* name, const char* value)
  888. {
  889. if (!variables_)
  890. variables_ = new pugi::xpath_variable_set();
  891. return variables_->set(name, value);
  892. }
  893. bool XPathQuery::SetVariable(const String& name, const XPathResultSet& value)
  894. {
  895. if (!variables_)
  896. variables_ = new pugi::xpath_variable_set();
  897. pugi::xpath_node_set* nodeSet = value.GetXPathNodeSet();
  898. if (!nodeSet)
  899. return false;
  900. return variables_->set(name.CString(), *nodeSet);
  901. }
  902. bool XPathQuery::SetQuery(const String& queryString, const String& variableString, bool bind)
  903. {
  904. if (!variableString.Empty())
  905. {
  906. Clear();
  907. variables_ = new pugi::xpath_variable_set();
  908. // Parse the variable string having format "name1:type1,name2:type2,..." where type is one of "Bool", "Float", "String", "ResultSet"
  909. Vector<String> vars = variableString.Split(',');
  910. for (Vector<String>::ConstIterator i = vars.Begin(); i != vars.End(); ++i)
  911. {
  912. Vector<String> tokens = i->Trimmed().Split(':');
  913. if (tokens.Size() != 2)
  914. continue;
  915. pugi::xpath_value_type type;
  916. if (tokens[1] == "Bool")
  917. type = pugi::xpath_type_boolean;
  918. else if (tokens[1] == "Float")
  919. type = pugi::xpath_type_number;
  920. else if (tokens[1] == "String")
  921. type = pugi::xpath_type_string;
  922. else if (tokens[1] == "ResultSet")
  923. type = pugi::xpath_type_node_set;
  924. else
  925. return false;
  926. if (!variables_->add(tokens[0].CString(), type))
  927. return false;
  928. }
  929. }
  930. queryString_ = queryString;
  931. if (bind)
  932. Bind();
  933. return true;
  934. }
  935. void XPathQuery::Clear()
  936. {
  937. queryString_.Clear();
  938. variables_.Reset();
  939. query_.Reset();
  940. }
  941. bool XPathQuery::EvaluateToBool(const XMLElement& element) const
  942. {
  943. if (!query_ || ((!element.GetFile() || !element.GetNode()) && !element.GetXPathNode()))
  944. return false;
  945. const pugi::xml_node& node = element.GetXPathNode() ? element.GetXPathNode()->node() : pugi::xml_node(element.GetNode());
  946. return query_->evaluate_boolean(node);
  947. }
  948. float XPathQuery::EvaluateToFloat(const XMLElement& element) const
  949. {
  950. if (!query_ || ((!element.GetFile() || !element.GetNode()) && !element.GetXPathNode()))
  951. return 0.0f;
  952. const pugi::xml_node& node = element.GetXPathNode() ? element.GetXPathNode()->node() : pugi::xml_node(element.GetNode());
  953. return (float)query_->evaluate_number(node);
  954. }
  955. String XPathQuery::EvaluateToString(const XMLElement& element) const
  956. {
  957. if (!query_ || ((!element.GetFile() || !element.GetNode()) && !element.GetXPathNode()))
  958. return String::EMPTY;
  959. const pugi::xml_node& node = element.GetXPathNode() ? element.GetXPathNode()->node() : pugi::xml_node(element.GetNode());
  960. String result;
  961. // First call get the size
  962. result.Reserve((unsigned)query_->evaluate_string(nullptr, 0, node));
  963. // Second call get the actual string
  964. query_->evaluate_string(const_cast<pugi::char_t*>(result.CString()), result.Capacity(), node);
  965. return result;
  966. }
  967. XPathResultSet XPathQuery::Evaluate(const XMLElement& element) const
  968. {
  969. if (!query_ || ((!element.GetFile() || !element.GetNode()) && !element.GetXPathNode()))
  970. return XPathResultSet();
  971. const pugi::xml_node& node = element.GetXPathNode() ? element.GetXPathNode()->node() : pugi::xml_node(element.GetNode());
  972. pugi::xpath_node_set result = query_->evaluate_node_set(node);
  973. return XPathResultSet(element.GetFile(), &result);
  974. }
  975. }