• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef IMAGE_IO_XML_XML_WRITER_H_  // NOLINT
2 #define IMAGE_IO_XML_XML_WRITER_H_  // NOLINT
3 
4 #include <sstream>
5 #include <string>
6 #include <vector>
7 
8 namespace photos_editing_formats {
9 namespace image_io {
10 
11 /// A very simple writer forXML that frees client code from worries about XML
12 /// formatting and bracket issues.
13 ///
14 /// The intended sequence of operations this writer supports is as follows:
15 /// 1. Start writing an element.
16 /// 2. Write any and all attribute names and values to that element.
17 /// 3. Write any content, or add a child element by starting to write another
18 ///    element (i.e., go to step 1). The "context" of the current element you
19 ///    are writing is saved on a stack. Once you start writing content or
20 ///    child elements you cannot add attribute names and values and expect to
21 ///    see them as such in the resulting XML.
22 /// 4. When you are done with the element, finish writing it. The element
23 ///    context stack is popped and you continue where you left off.
24 ///
25 /// When writing element content and attribute values no XML escaping of any
26 /// kind is done. If you need to do that, do it yourself.
27 class XmlWriter {
28  public:
29   /// @param os The stream to which the XML is written.
30   explicit XmlWriter(std::ostream& os);
31 
32   /// @return The number of elements that have been written.
GetElementCount()33   size_t GetElementCount() const { return element_count_; }
34 
35   /// @return The depth of the element stack.
GetElementDepth()36   size_t GetElementDepth() const { return element_data_.size(); }
37 
38   /// @return The quote mark used when writing attribute values. The default
39   /// value set up by the constructor is the double quote (").
GetQuoteMark()40   char GetQuoteMark() const { return quote_mark_; }
41 
42   /// @param quote_park The new quote mark to use when writing attribute values.
SetQuoteMark(char quote_mark)43   void SetQuoteMark(char quote_mark) { quote_mark_ = quote_mark; }
44 
45   /// @return The leading indent written before the current element.
GetIndent()46   const std::string& GetIndent() const { return indent_; }
47 
48   /// Once you are done writing your elements, you can call this function to
49   /// finish writing of all open elements. After this call, the string contained
50   /// in the ostream you passed to the constructor is fully formed XML.
FinishWriting()51   void FinishWriting() { FinishWritingElementsToDepth(0); }
52 
53   /// @return Whether the writing of XML can be considered done.
IsDone()54   bool IsDone() const { return indent_.empty(); }
55 
56   /// Writes an xmlns attribute to the currently open element.
57   /// @param prefix The prefix you intend to use for elements/attributes.
58   /// @param uri The uri of the namespace.
59   void WriteXmlns(const std::string& prefix, const std::string& uri);
60 
61   /// Starts writing a new child element of the current element. Immediately
62   /// after this function you can add attributes to the element using one of the
63   /// AddAttributeNameAndValue() functions.
64   /// @param element_name The name of the element to write.
65   /// @return The number of open elements on the stack at the start of this
66   /// function. You can use this value with the FinishWritingElementToDepth()
67   /// function to finish writing this element and any open descendents.
68   size_t StartWritingElement(const std::string& element_name);
69 
70   /// Finishes writing the element and returns the "context" to the previously
71   /// open element so that you can continue adding child elements (via a call to
72   /// StartWritingElement()) or content (via a call to WriteContent()).
73   void FinishWritingElement();
74 
75   /// Finishes writing any elements that exist in the stack of open elements
76   /// above the depth value parameter.
77   /// @param depth The depth above which to finish writing open elements.
78   void FinishWritingElementsToDepth(size_t depth);
79 
80   /// Starts writing the elements in the vector, leaving the last open for you
81   /// to add attributes or other elements to.
82   /// @param element_names The array of element names to start writing.
83   /// @return The number of open elements on the stack at the start of this
84   /// function. You can use this value with the FinishWritingElementToDepth()
85   /// function to finish writing this element and any open descendents.
86   size_t StartWritingElements(const std::vector<std::string>& element_names);
87 
88   /// A template method function that allows you to start an element, add the
89   /// value as its content and then finish writing the element. This is useful
90   /// if you are writing property values as elements.
91   /// @param element_name The name of the element to write.
92   /// @param value The value that is converted to a string and written as the
93   /// element's content.
94   template <class T>
WriteElementAndContent(const std::string & element_name,const T & value)95   void WriteElementAndContent(const std::string& element_name, const T& value) {
96     std::stringstream ss;
97     ss << value;
98     WriteElementAndContent(element_name, ss.str());
99   }
100 
101   /// Starts writing an element with the given name, adds the string value as
102   /// its content and then finishes writing the element. This is useful
103   /// if you are writing property values as elements.
104   /// @param element_name The name of the element to write.
105   /// @param value The value to use as the element's content.
106   void WriteElementAndContent(const std::string& element_name,
107                               const std::string& content);
108 
109   /// Writes the string as the currently open element's content. Note that if
110   /// you add child elements to the open element, the content you will see when
111   /// you read your element will have the whitespace due to the indent string.
112   /// @param content The content to write to the currently open element.
113   void WriteContent(const std::string& content);
114 
115   /// A template method function that allows you to add an attribute name and
116   /// value to a just-opened element. Attributes must be added to an element
117   /// before adding content or child elements.
118   /// @param name The name of the attribute to add.
119   /// @param value The value of the attribute. This value is converted to a
120   /// string and enclosed in the quote marks from the GetQuoteMark() function.
121   template <class T>
WriteAttributeNameAndValue(const std::string & name,const T & value)122   void WriteAttributeNameAndValue(const std::string& name, const T& value) {
123     std::stringstream ss;
124     ss << GetQuoteMark() << value << GetQuoteMark();
125     WriteAttributeNameAndValue(name, ss.str(), false);
126   }
127 
128   /// Adds an attribute name and value to a just-opened element. Attributes must
129   /// be added to an element before adding content or child elements.
130   /// @param name The name of the attribute to add.
131   /// @param value The value of the attribute.
132   /// @param add_quote_marks Whether quote marks should be added before and
133   /// after the value. If this value is false, it is assumed that the client
134   /// code has added them before calling this function.
135   void WriteAttributeNameAndValue(const std::string& name,
136                                   const std::string& value,
137                                   bool add_quote_marks = true);
138 
139   /// Adds an attribute name and equal sign to the just-opened element.
140   /// Attributes must be added to an element before adding content or child
141   /// elements. Clients that use this function must call WriteAttributeValue()
142   /// with appropriate values to define a legally quoted value. This function
143   /// is useful for writing attribute with extremely long values that might not
144   /// be efficient to store as a single string value.
145   /// @param name The name of the attribute to add.
146   void WriteAttributeName(const std::string& name);
147 
148   /// Writes the attribute value with optional quote marks on either side. This
149   /// function may be repeatedly called with appropriate valeus for the leading
150   /// and trailing quote mark flags to write extremely long attribute values.
151   /// @param add_leading_quote_mark Whether to add a leading quote mark.
152   /// @param value The (probably partial) value to write.
153   /// @param add_trailing_quote_mark Whether to add a trailing quote mark.
154   void WriteAttributeValue(bool add_leading_quote_mark,
155                            const std::string& value,
156                            bool add_trailing_quote_mark);
157 
158   /// Writes a comment to the xml stream. Note that writing a comment is like
159   /// adding a child node/element to the current element. If the current element
160   /// is still open for names/values, it will be closed before writing it - i.e.
161   /// you can't add attributes to an element after calling this function.
162   /// @param comment The text of the comment to write.
163   void WriteComment(const std::string& comment);
164 
165  private:
166   /// The data that is known about each element on the stack.
167   struct ElementData {
ElementDataElementData168     ElementData(const std::string& name_)
169         : name(name_),
170           has_attributes(false),
171           has_content(false),
172           has_children(false) {}
173     std::string name;
174     bool has_attributes;
175     bool has_content;
176     bool has_children;
177   };
178 
179   /// Determines if the start element syntax of the current element needs to
180   /// be closed with a bracket so that content or child elements or comments
181   /// can be added to the element.
182   /// @param with_trailing_newline Whether a newline is added after the bracket.
183   /// @return Whether the element's start syntax was closed with a bracket.
184   bool MaybeWriteCloseBracket(bool with_trailing_newline);
185 
186   /// The stream to which everything is written.
187   std::ostream& os_;
188 
189   /// The indent to write before elements and attribute names/values.
190   std::string indent_;
191 
192   /// The currently open elements being written.
193   std::vector<ElementData> element_data_;
194 
195   /// The number of elements that have been written.
196   size_t element_count_;
197 
198   /// The quote mark to use around attribute values by default.
199   char quote_mark_;
200 };
201 
202 }  // namespace image_io
203 }  // namespace photos_editing_formats
204 
205 #endif  // IMAGE_IO_XML_XML_WRITER_H_  // NOLINT
206