XMLParser.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #include "../../Include/RmlUi/Core/XMLParser.h"
  2. #include "../../Include/RmlUi/Core/Element.h"
  3. #include "../../Include/RmlUi/Core/Factory.h"
  4. #include "../../Include/RmlUi/Core/Log.h"
  5. #include "../../Include/RmlUi/Core/Profiling.h"
  6. #include "../../Include/RmlUi/Core/Stream.h"
  7. #include "../../Include/RmlUi/Core/Types.h"
  8. #include "../../Include/RmlUi/Core/URL.h"
  9. #include "../../Include/RmlUi/Core/XMLNodeHandler.h"
  10. #include "ControlledLifetimeResource.h"
  11. #include "DocumentHeader.h"
  12. namespace Rml {
  13. struct XmlParserData {
  14. UnorderedMap<String, SharedPtr<XMLNodeHandler>> node_handlers;
  15. UnorderedSet<String> cdata_tags;
  16. SharedPtr<XMLNodeHandler> default_node_handler;
  17. };
  18. static ControlledLifetimeResource<XmlParserData> xml_parser_data;
  19. XMLParser::XMLParser(Element* root)
  20. {
  21. for (const String& cdata_tag : xml_parser_data->cdata_tags)
  22. RegisterCDATATag(cdata_tag);
  23. for (const String& name : Factory::GetStructuralDataViewAttributeNames())
  24. RegisterInnerXMLAttribute(name);
  25. // Add the first frame.
  26. ParseFrame frame;
  27. frame.element = root;
  28. if (root != nullptr)
  29. {
  30. frame.tag = root->GetTagName();
  31. auto itr = xml_parser_data->node_handlers.find(root->GetTagName());
  32. if (itr != xml_parser_data->node_handlers.end())
  33. {
  34. frame.node_handler = itr->second.get();
  35. }
  36. else
  37. {
  38. frame.node_handler = xml_parser_data->default_node_handler.get();
  39. }
  40. }
  41. stack.push(frame);
  42. active_handler = nullptr;
  43. header = MakeUnique<DocumentHeader>();
  44. }
  45. XMLParser::~XMLParser() {}
  46. void XMLParser::RegisterPersistentCDATATag(const String& _tag)
  47. {
  48. if (!xml_parser_data)
  49. xml_parser_data.Initialize();
  50. String tag = StringUtilities::ToLower(_tag);
  51. if (tag.empty())
  52. return;
  53. xml_parser_data->cdata_tags.insert(tag);
  54. }
  55. XMLNodeHandler* XMLParser::RegisterNodeHandler(const String& _tag, SharedPtr<XMLNodeHandler> handler)
  56. {
  57. if (!xml_parser_data)
  58. xml_parser_data.Initialize();
  59. String tag = StringUtilities::ToLower(_tag);
  60. // Check for a default node registration.
  61. if (tag.empty())
  62. {
  63. xml_parser_data->default_node_handler = std::move(handler);
  64. return xml_parser_data->default_node_handler.get();
  65. }
  66. XMLNodeHandler* result = handler.get();
  67. xml_parser_data->node_handlers[tag] = std::move(handler);
  68. return result;
  69. }
  70. XMLNodeHandler* XMLParser::GetNodeHandler(const String& tag)
  71. {
  72. auto it = xml_parser_data->node_handlers.find(tag);
  73. if (it != xml_parser_data->node_handlers.end())
  74. return it->second.get();
  75. return nullptr;
  76. }
  77. void XMLParser::ReleaseHandlers()
  78. {
  79. xml_parser_data.Shutdown();
  80. }
  81. DocumentHeader* XMLParser::GetDocumentHeader()
  82. {
  83. return header.get();
  84. }
  85. void XMLParser::PushDefaultHandler()
  86. {
  87. active_handler = xml_parser_data->default_node_handler.get();
  88. }
  89. bool XMLParser::PushHandler(const String& tag)
  90. {
  91. auto it = xml_parser_data->node_handlers.find(StringUtilities::ToLower(tag));
  92. if (it == xml_parser_data->node_handlers.end())
  93. return false;
  94. active_handler = it->second.get();
  95. return true;
  96. }
  97. const XMLParser::ParseFrame* XMLParser::GetParseFrame() const
  98. {
  99. return &stack.top();
  100. }
  101. const URL& XMLParser::GetSourceURL() const
  102. {
  103. RMLUI_ASSERT(GetSourceURLPtr());
  104. return *GetSourceURLPtr();
  105. }
  106. void XMLParser::HandleElementStart(const String& _name, const XMLAttributes& attributes)
  107. {
  108. RMLUI_ZoneScoped;
  109. const String name = StringUtilities::ToLower(_name);
  110. // Check for a specific handler that will override the child handler.
  111. auto itr = xml_parser_data->node_handlers.find(name);
  112. if (itr != xml_parser_data->node_handlers.end())
  113. active_handler = itr->second.get();
  114. // Store the current active handler, so we can use it through this function (as active handler may change)
  115. XMLNodeHandler* node_handler = active_handler;
  116. Element* element = nullptr;
  117. // Get the handler to handle the open tag
  118. if (node_handler)
  119. {
  120. element = node_handler->ElementStart(this, name, attributes);
  121. }
  122. // Push onto the stack
  123. ParseFrame frame;
  124. frame.node_handler = node_handler;
  125. frame.child_handler = active_handler;
  126. frame.element = (element ? element : stack.top().element);
  127. frame.tag = name;
  128. stack.push(frame);
  129. }
  130. void XMLParser::HandleElementEnd(const String& _name)
  131. {
  132. RMLUI_ZoneScoped;
  133. String name = StringUtilities::ToLower(_name);
  134. // Copy the top of the stack
  135. ParseFrame frame = stack.top();
  136. // Pop the frame
  137. stack.pop();
  138. // Restore active handler to the previous frame's child handler
  139. active_handler = stack.top().child_handler;
  140. // Check frame names
  141. if (name != frame.tag)
  142. {
  143. Log::Message(Log::LT_ERROR, "Closing tag '%s' mismatched on %s:%d was expecting '%s'.", name.c_str(), GetSourceURL().GetURL().c_str(),
  144. GetLineNumber(), frame.tag.c_str());
  145. }
  146. // Call element end handler
  147. if (frame.node_handler)
  148. {
  149. frame.node_handler->ElementEnd(this, name);
  150. }
  151. }
  152. void XMLParser::HandleData(const String& data, XMLDataType type)
  153. {
  154. RMLUI_ZoneScoped;
  155. if (stack.top().node_handler)
  156. stack.top().node_handler->ElementData(this, data, type);
  157. }
  158. } // namespace Rml