rapidjson::Document toJSONImpl()

in extensions/windows-event-log/wel/JSONUtils.cpp [108:197]


rapidjson::Document toJSONImpl(const pugi::xml_node& root, bool flatten) {
  rapidjson::Document doc{rapidjson::kObjectType};

  auto event_xml = root.child("Event");

  {
    auto system_xml = event_xml.child("System");
    auto& system = flatten ? doc : doc.AddMember("System", rapidjson::kObjectType, doc.GetAllocator())["System"];

    {
      auto provider_xml = system_xml.child("Provider");
      auto& provider = flatten ? doc : system.AddMember("Provider", rapidjson::kObjectType, doc.GetAllocator())["Provider"];
      provider.AddMember("Name", rapidjson::StringRef(provider_xml.attribute("Name").value()), doc.GetAllocator());
      provider.AddMember("Guid", rapidjson::StringRef(provider_xml.attribute("Guid").value()), doc.GetAllocator());
    }

    system.AddMember("EventID", rapidjson::StringRef(system_xml.child("EventID").text().get()), doc.GetAllocator());
    system.AddMember("Version", rapidjson::StringRef(system_xml.child("Version").text().get()), doc.GetAllocator());
    system.AddMember("Level", rapidjson::StringRef(system_xml.child("Level").text().get()), doc.GetAllocator());
    system.AddMember("Task", rapidjson::StringRef(system_xml.child("Task").text().get()), doc.GetAllocator());
    system.AddMember("Opcode", rapidjson::StringRef(system_xml.child("Opcode").text().get()), doc.GetAllocator());
    system.AddMember("Keywords", rapidjson::StringRef(system_xml.child("Keywords").text().get()), doc.GetAllocator());

    {
      auto timeCreated_xml = system_xml.child("TimeCreated");
      auto& timeCreated = flatten ? doc : system.AddMember("TimeCreated", rapidjson::kObjectType, doc.GetAllocator())["TimeCreated"];
      timeCreated.AddMember("SystemTime", rapidjson::StringRef(timeCreated_xml.attribute("SystemTime").value()), doc.GetAllocator());
    }

    system.AddMember("EventRecordID", rapidjson::StringRef(system_xml.child("EventRecordID").text().get()), doc.GetAllocator());

    {
      auto correlation_xml = system_xml.child("Correlation");
      auto& correlation = flatten ? doc : system.AddMember("Correlation", rapidjson::kObjectType, doc.GetAllocator())["Correlation"];
      const auto activity_id = correlation_xml.attribute("ActivityID");
      if (!activity_id.empty()) {
        correlation.AddMember("ActivityID", rapidjson::StringRef(activity_id.value()), doc.GetAllocator());
      }
    }

    {
      auto execution_xml = system_xml.child("Execution");
      auto& execution = flatten ? doc : system.AddMember("Execution", rapidjson::kObjectType, doc.GetAllocator())["Execution"];
      execution.AddMember("ProcessID", rapidjson::StringRef(execution_xml.attribute("ProcessID").value()), doc.GetAllocator());
      execution.AddMember("ThreadID", rapidjson::StringRef(execution_xml.attribute("ThreadID").value()), doc.GetAllocator());
    }

    system.AddMember("Channel", rapidjson::StringRef(system_xml.child("Channel").text().get()), doc.GetAllocator());
    system.AddMember("Computer", rapidjson::StringRef(system_xml.child("Computer").text().get()), doc.GetAllocator());

    {
      auto security_xml = system_xml.child("Security");
      auto& security = flatten ? doc : system.AddMember("Security", rapidjson::kObjectType, doc.GetAllocator())["Security"];
      security.AddMember("UserID", rapidjson::StringRef(security_xml.attribute("UserID").value()), doc.GetAllocator());
    }
  }

  {
    auto eventData_xml = event_xml.child("EventData");
    if (flatten) {
      for (const auto& event_data_child : eventData_xml.children()) {
        std::string key = "EventData";
        if (auto name_attr = event_data_child.attribute("Name"); !name_attr.empty()) {
          key = utils::string::join_pack(key, ".", name_attr.value());
        }

        doc.AddMember(rapidjson::Value(createUniqueKey(key, doc), doc.GetAllocator()).Move(), rapidjson::StringRef(event_data_child.text().get()), doc.GetAllocator());
      }
    } else {
      doc.AddMember("EventData", rapidjson::kArrayType, doc.GetAllocator());
      for (const auto& event_data_child : eventData_xml.children()) {
        auto name_attr = event_data_child.attribute("Name");
        rapidjson::Value item(rapidjson::kObjectType);
        item.AddMember("Name", rapidjson::StringRef(name_attr.value()), doc.GetAllocator());
        item.AddMember("Content", rapidjson::StringRef(event_data_child.text().get()), doc.GetAllocator());
        item.AddMember("Type", rapidjson::StringRef(event_data_child.name()), doc.GetAllocator());
        doc["EventData"].PushBack(item, doc.GetAllocator());  // we need to re-query EventData because a reference to it wouldn't be stable
      }
    }
  }

  const auto userdata_xml = event_xml.child("UserData");
  if (!userdata_xml.empty()) {
    auto& userdata = flatten ? doc : doc.AddMember("UserData", rapidjson::kObjectType, doc.GetAllocator())["UserData"];
    auto prefix = flatten ? std::optional("UserData.") : std::nullopt;
    simplifiedGenericXmlToJson(userdata_xml, userdata, doc.GetAllocator(), prefix);
  }

  return doc;
}