blob: 7571fe780b9ebfdf7353c9b8fcaf77793c11624a [file] [log] [blame]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SERVICES_DATA_DECODER_PUBLIC_CPP_XML_DOM_H_
#define SERVICES_DATA_DECODER_PUBLIC_CPP_XML_DOM_H_
#include <map>
#include <memory>
#include <optional>
#include <sstream>
#include <string>
#include <string_view>
#include <variant>
#include <vector>
#include "base/check.h"
#include "base/memory/raw_ptr.h"
#include "base/types/pass_key.h"
#include "third_party/abseil-cpp/absl/container/flat_hash_map.h"
class XmlDocument;
namespace data_decoder {
class XmlDomTest; // Forward declaration for friending
}
class XmlNode {
public:
enum class Type { kELEMENT, kTEXT };
~XmlNode();
// Get the type of the node
Type GetType() const;
// Get the tag name (only for ELEMENT nodes)
const std::string& GetTagName() const;
// Get the text content (only for TEXT nodes)
const std::string& GetTextContent() const;
// Get an attribute value by name (only for ELEMENT nodes)
std::optional<std::string> GetAttribute(std::string_view name) const;
// Get all child nodes
const std::vector<std::unique_ptr<XmlNode>>& GetChildren() const;
// Get parent node
const XmlNode* GetParent() const;
// Find all direct child elements with a specific tag name
std::vector<const XmlNode*> GetChildrenByTagName(
std::string_view tag_name) const;
// Get the first direct child element with a specific tag name
const XmlNode* GetFirstChildByTagName(std::string_view tag_name) const;
// Testing methods.
void AddChildForTesting(std::unique_ptr<XmlNode> child);
void SetAttributeForTesting(const std::string& name,
const std::string& value);
private:
friend class XmlDocument;
// Private constructor for all node types.
XmlNode(base::PassKey<XmlDocument>,
Type type,
const std::string& tag_name,
const std::string& text_content);
struct ElementData {
ElementData();
explicit ElementData(std::string tag_name);
ElementData(ElementData&&);
ElementData& operator=(ElementData&&);
~ElementData();
std::string tag;
absl::flat_hash_map<std::string, std::string> attributes;
std::vector<std::unique_ptr<XmlNode>> children;
};
std::variant<ElementData, std::string> data_;
raw_ptr<XmlNode> parent_;
};
class XmlDocument {
public:
XmlDocument();
~XmlDocument();
// Disallow copy and assign
XmlDocument(const XmlDocument&) = delete;
XmlDocument& operator=(const XmlDocument&) = delete;
// Allow move
XmlDocument(XmlDocument&&);
XmlDocument& operator=(XmlDocument&&);
// Get the root element of the document
const XmlNode* GetRoot() const;
// Find the first element with a given tag name (DFS)
const XmlNode* FindFirstElementByTagName(std::string_view tag_name) const;
// Testing methods.
void SetRootForTesting(std::unique_ptr<XmlNode> root);
static std::unique_ptr<XmlNode> CreateElementNodeForTesting(
const std::string& tag_name);
static std::unique_ptr<XmlNode> CreateTextNodeForTesting(
const std::string& text_content);
private:
std::unique_ptr<XmlNode> root_;
const XmlNode* FindFirstElementByTagNameRecursive(
const XmlNode* node,
std::string_view tag_name) const;
};
#endif // SERVICES_DATA_DECODER_PUBLIC_CPP_XML_DOM_H_