1 // Copyright 2015 The Weave Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/notification/xml_node.h"
6 
7 #include <base/strings/stringprintf.h>
8 
9 #include "src/string_utils.h"
10 
11 namespace weave {
12 
XmlNode(const std::string & name,std::map<std::string,std::string> attributes)13 XmlNode::XmlNode(const std::string& name,
14                  std::map<std::string, std::string> attributes)
15     : name_{name}, attributes_{std::move(attributes)} {}
16 
name() const17 const std::string& XmlNode::name() const {
18   return name_;
19 }
20 
text() const21 const std::string& XmlNode::text() const {
22   return text_;
23 }
24 
attributes() const25 const std::map<std::string, std::string>& XmlNode::attributes() const {
26   return attributes_;
27 }
28 
children() const29 const std::vector<std::unique_ptr<XmlNode>>& XmlNode::children() const {
30   return children_;
31 }
32 
GetAttribute(const std::string & name,std::string * value) const33 bool XmlNode::GetAttribute(const std::string& name, std::string* value) const {
34   auto p = attributes_.find(name);
35   if (p == attributes_.end())
36     return false;
37 
38   *value = p->second;
39   return true;
40 }
41 
GetAttributeOrEmpty(const std::string & name) const42 std::string XmlNode::GetAttributeOrEmpty(const std::string& name) const {
43   std::string value;
44   GetAttribute(name, &value);
45   return value;
46 }
47 
FindFirstChild(const std::string & name_path,bool recursive) const48 const XmlNode* XmlNode::FindFirstChild(const std::string& name_path,
49                                        bool recursive) const {
50   return FindChildHelper(name_path, recursive, nullptr);
51 }
52 
FindChildren(const std::string & name_path,bool recursive) const53 std::vector<const XmlNode*> XmlNode::FindChildren(const std::string& name_path,
54                                                   bool recursive) const {
55   std::vector<const XmlNode*> children;
56   FindChildHelper(name_path, recursive, &children);
57   return children;
58 }
59 
FindChildHelper(const std::string & name_path,bool recursive,std::vector<const XmlNode * > * children) const60 const XmlNode* XmlNode::FindChildHelper(
61     const std::string& name_path,
62     bool recursive,
63     std::vector<const XmlNode*>* children) const {
64   auto parts = SplitAtFirst(name_path, "/", false);
65   const std::string& name = parts.first;
66   const std::string& rest_of_path = parts.second;
67   for (const auto& child : children_) {
68     const XmlNode* found_node = nullptr;
69     if (child->name() == name) {
70       if (rest_of_path.empty()) {
71         found_node = child.get();
72       } else {
73         found_node = child->FindChildHelper(rest_of_path, false, children);
74       }
75     } else if (recursive) {
76       found_node = child->FindChildHelper(name_path, true, children);
77     }
78 
79     if (found_node) {
80       if (!children)
81         return found_node;
82       children->push_back(found_node);
83     }
84   }
85   return nullptr;
86 }
87 
SetText(const std::string & text)88 void XmlNode::SetText(const std::string& text) {
89   text_ = text;
90 }
91 
AppendText(const std::string & text)92 void XmlNode::AppendText(const std::string& text) {
93   text_ += text;
94 }
95 
AddChild(std::unique_ptr<XmlNode> child)96 void XmlNode::AddChild(std::unique_ptr<XmlNode> child) {
97   child->parent_ = this;
98   children_.push_back(std::move(child));
99 }
100 
ToString() const101 std::string XmlNode::ToString() const {
102   std::string xml = base::StringPrintf("<%s", name_.c_str());
103   for (const auto& pair : attributes_) {
104     base::StringAppendF(&xml, " %s=\"%s\"", pair.first.c_str(),
105                         pair.second.c_str());
106   }
107   if (text_.empty() && children_.empty()) {
108     xml += "/>";
109   } else {
110     xml += '>';
111     if (!text_.empty()) {
112       xml += text_;
113     }
114     for (const auto& child : children_) {
115       xml += child->ToString();
116     }
117     base::StringAppendF(&xml, "</%s>", name_.c_str());
118   }
119   return xml;
120 }
121 
122 }  // namespace weave
123