|  | // Copyright 2015 The Weave Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "src/notification/xml_node.h" | 
|  |  | 
|  | #include <base/strings/stringprintf.h> | 
|  |  | 
|  | #include "src/string_utils.h" | 
|  |  | 
|  | namespace weave { | 
|  |  | 
|  | XmlNode::XmlNode(const std::string& name, | 
|  | std::map<std::string, std::string> attributes) | 
|  | : name_{name}, attributes_{std::move(attributes)} {} | 
|  |  | 
|  | const std::string& XmlNode::name() const { | 
|  | return name_; | 
|  | } | 
|  |  | 
|  | const std::string& XmlNode::text() const { | 
|  | return text_; | 
|  | } | 
|  |  | 
|  | const std::map<std::string, std::string>& XmlNode::attributes() const { | 
|  | return attributes_; | 
|  | } | 
|  |  | 
|  | const std::vector<std::unique_ptr<XmlNode>>& XmlNode::children() const { | 
|  | return children_; | 
|  | } | 
|  |  | 
|  | bool XmlNode::GetAttribute(const std::string& name, std::string* value) const { | 
|  | auto p = attributes_.find(name); | 
|  | if (p == attributes_.end()) | 
|  | return false; | 
|  |  | 
|  | *value = p->second; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | std::string XmlNode::GetAttributeOrEmpty(const std::string& name) const { | 
|  | std::string value; | 
|  | GetAttribute(name, &value); | 
|  | return value; | 
|  | } | 
|  |  | 
|  | const XmlNode* XmlNode::FindFirstChild(const std::string& name_path, | 
|  | bool recursive) const { | 
|  | return FindChildHelper(name_path, recursive, nullptr); | 
|  | } | 
|  |  | 
|  | std::vector<const XmlNode*> XmlNode::FindChildren(const std::string& name_path, | 
|  | bool recursive) const { | 
|  | std::vector<const XmlNode*> children; | 
|  | FindChildHelper(name_path, recursive, &children); | 
|  | return children; | 
|  | } | 
|  |  | 
|  | const XmlNode* XmlNode::FindChildHelper( | 
|  | const std::string& name_path, | 
|  | bool recursive, | 
|  | std::vector<const XmlNode*>* children) const { | 
|  | auto parts = SplitAtFirst(name_path, "/", false); | 
|  | const std::string& name = parts.first; | 
|  | const std::string& rest_of_path = parts.second; | 
|  | for (const auto& child : children_) { | 
|  | const XmlNode* found_node = nullptr; | 
|  | if (child->name() == name) { | 
|  | if (rest_of_path.empty()) { | 
|  | found_node = child.get(); | 
|  | } else { | 
|  | found_node = child->FindChildHelper(rest_of_path, false, children); | 
|  | } | 
|  | } else if (recursive) { | 
|  | found_node = child->FindChildHelper(name_path, true, children); | 
|  | } | 
|  |  | 
|  | if (found_node) { | 
|  | if (!children) | 
|  | return found_node; | 
|  | children->push_back(found_node); | 
|  | } | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | void XmlNode::SetText(const std::string& text) { | 
|  | text_ = text; | 
|  | } | 
|  |  | 
|  | void XmlNode::AppendText(const std::string& text) { | 
|  | text_ += text; | 
|  | } | 
|  |  | 
|  | void XmlNode::AddChild(std::unique_ptr<XmlNode> child) { | 
|  | child->parent_ = this; | 
|  | children_.push_back(std::move(child)); | 
|  | } | 
|  |  | 
|  | std::string XmlNode::ToString() const { | 
|  | std::string xml = base::StringPrintf("<%s", name_.c_str()); | 
|  | for (const auto& pair : attributes_) { | 
|  | base::StringAppendF(&xml, " %s=\"%s\"", pair.first.c_str(), | 
|  | pair.second.c_str()); | 
|  | } | 
|  | if (text_.empty() && children_.empty()) { | 
|  | xml += "/>"; | 
|  | } else { | 
|  | xml += '>'; | 
|  | if (!text_.empty()) { | 
|  | xml += text_; | 
|  | } | 
|  | for (const auto& child : children_) { | 
|  | xml += child->ToString(); | 
|  | } | 
|  | base::StringAppendF(&xml, "</%s>", name_.c_str()); | 
|  | } | 
|  | return xml; | 
|  | } | 
|  |  | 
|  | }  // namespace weave |