1 // Copyright (c) 2012 The Chromium 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 #ifndef THIRD_PARTY_LIBXML_CHROMIUM_LIBXML_UTILS_H_ 6 #define THIRD_PARTY_LIBXML_CHROMIUM_LIBXML_UTILS_H_ 7 #pragma once 8 9 #include <string> 10 11 #include "libxml/xmlreader.h" 12 #include "libxml/xmlwriter.h" 13 14 // Converts a libxml xmlChar* into a UTF-8 std::string. 15 // NULL inputs produce an empty string. 16 std::string XmlStringToStdString(const xmlChar* xmlstring); 17 18 // libxml uses a global error function pointer for reporting errors. 19 // A ScopedXmlErrorFunc object lets you change the global error pointer 20 // for the duration of the object's lifetime. 21 class ScopedXmlErrorFunc { 22 public: ScopedXmlErrorFunc(void * context,xmlGenericErrorFunc func)23 ScopedXmlErrorFunc(void* context, xmlGenericErrorFunc func) { 24 old_error_func_ = xmlGenericError; 25 old_error_context_ = xmlGenericErrorContext; 26 xmlSetGenericErrorFunc(context, func); 27 } ~ScopedXmlErrorFunc()28 ~ScopedXmlErrorFunc() { 29 xmlSetGenericErrorFunc(old_error_context_, old_error_func_); 30 } 31 32 private: 33 xmlGenericErrorFunc old_error_func_; 34 void* old_error_context_; 35 }; 36 37 // XmlReader is a wrapper class around libxml's xmlReader, 38 // providing a simplified C++ API. 39 class XmlReader { 40 public: 41 XmlReader(); 42 ~XmlReader(); 43 44 // Load a document into the reader from memory. |input| must be UTF-8 and 45 // exist for the lifetime of this object. Returns false on error. 46 // TODO(evanm): handle encodings other than UTF-8? 47 bool Load(const std::string& input); 48 49 // Load a document into the reader from a file. Returns false on error. 50 bool LoadFile(const std::string& file_path); 51 52 // Wrappers around libxml functions ----------------------------------------- 53 54 // Read() advances to the next node. Returns false on EOF or error. Read()55 bool Read() { return xmlTextReaderRead(reader_) == 1; } 56 57 // Next(), when pointing at an opening tag, advances to the node after 58 // the matching closing tag. Returns false on EOF or error. Next()59 bool Next() { return xmlTextReaderNext(reader_) == 1; } 60 61 // Return the depth in the tree of the current node. Depth()62 int Depth() { return xmlTextReaderDepth(reader_); } 63 64 // Returns the "local" name of the current node. 65 // For a tag like <foo:bar>, this is the string "foo:bar". NodeName()66 std::string NodeName() { 67 return XmlStringToStdString(xmlTextReaderConstLocalName(reader_)); 68 } 69 70 // When pointing at a tag, retrieves the value of an attribute. 71 // Returns false on failure. 72 // E.g. for <foo bar:baz="a">, NodeAttribute("bar:baz", &value) 73 // returns true and |value| is set to "a". 74 bool NodeAttribute(const char* name, std::string* value); 75 76 // Returns true if the node is a closing element (e.g. </foo>). 77 bool IsClosingElement(); 78 79 // Helper functions not provided by libxml ---------------------------------- 80 81 // Return the string content within an element. 82 // "<foo>bar</foo>" is a sequence of three nodes: 83 // (1) open tag, (2) text, (3) close tag. 84 // With the reader currently at (1), this returns the text of (2), 85 // and advances past (3). 86 // Returns false on error. 87 bool ReadElementContent(std::string* content); 88 89 // Skip to the next opening tag, returning false if we reach a closing 90 // tag or EOF first. 91 // If currently on an opening tag, doesn't advance at all. 92 bool SkipToElement(); 93 94 private: 95 // Returns the libxml node type of the current node. NodeType()96 int NodeType() { return xmlTextReaderNodeType(reader_); } 97 98 // The underlying libxml xmlTextReader. 99 xmlTextReaderPtr reader_; 100 }; 101 102 // XmlWriter is a wrapper class around libxml's xmlWriter, 103 // providing a simplified C++ API. 104 // StartWriting must be called before other methods, and StopWriting 105 // must be called before GetWrittenString() will return results. 106 class XmlWriter { 107 public: 108 XmlWriter(); 109 ~XmlWriter(); 110 111 // Allocates the xmlTextWriter and an xmlBuffer and starts an XML document. 112 // This must be called before any other functions. By default, indenting is 113 // set to true. 114 void StartWriting(); 115 116 // Ends the XML document and frees the xmlTextWriter. 117 // This must be called before GetWrittenString() is called. 118 void StopWriting(); 119 // Wrappers around libxml functions ----------------------------------------- 120 121 // All following elements will be indented to match their depth. StartIndenting()122 void StartIndenting() { xmlTextWriterSetIndent(writer_, 1); } 123 124 // All follow elements will not be indented. StopIndenting()125 void StopIndenting() { xmlTextWriterSetIndent(writer_, 0); } 126 127 // Start an element with the given name. All future elements added will be 128 // children of this element, until it is ended. Returns false on error. StartElement(const std::string & element_name)129 bool StartElement(const std::string& element_name) { 130 return xmlTextWriterStartElement(writer_, 131 BAD_CAST element_name.c_str()) >= 0; 132 } 133 134 // Ends the current open element. Returns false on error. EndElement()135 bool EndElement() { 136 return xmlTextWriterEndElement(writer_) >= 0; 137 } 138 139 // Appends to the content of the current open element. AppendElementContent(const std::string & content)140 bool AppendElementContent(const std::string& content) { 141 return xmlTextWriterWriteString(writer_, 142 BAD_CAST content.c_str()) >= 0; 143 } 144 145 // Adds an attribute to the current open element. Returns false on error. AddAttribute(const std::string & attribute_name,const std::string & attribute_value)146 bool AddAttribute(const std::string& attribute_name, 147 const std::string& attribute_value) { 148 return xmlTextWriterWriteAttribute(writer_, 149 BAD_CAST attribute_name.c_str(), 150 BAD_CAST attribute_value.c_str()) >= 0; 151 } 152 153 // Adds a new element with name |element_name| and content |content| 154 // to the buffer. Example: <|element_name|>|content|</|element_name|> 155 // Returns false on errors. WriteElement(const std::string & element_name,const std::string & content)156 bool WriteElement(const std::string& element_name, 157 const std::string& content) { 158 return xmlTextWriterWriteElement(writer_, 159 BAD_CAST element_name.c_str(), 160 BAD_CAST content.c_str()) >= 0; 161 } 162 163 // Helper functions not provided by xmlTextWriter --------------------------- 164 165 // Returns the string that has been written to the buffer. GetWrittenString()166 std::string GetWrittenString() { 167 if (buffer_ == NULL) 168 return ""; 169 return XmlStringToStdString(buffer_->content); 170 } 171 172 private: 173 // The underlying libxml xmlTextWriter. 174 xmlTextWriterPtr writer_; 175 176 // Stores the output. 177 xmlBufferPtr buffer_; 178 }; 179 180 #endif // THIRD_PARTY_LIBXML_CHROMIUM_INCLUDE_LIBXML_LIBXML_UTILS_H_ 181