1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
3 #include "cmXMLParser.h"
10 #include <cm3p/expat.h>
12 #include "cmsys/FStream.hxx"
14 cmXMLParser::cmXMLParser()
16 this->Parser = nullptr;
18 this->ReportCallback = nullptr;
19 this->ReportCallbackData = nullptr;
22 cmXMLParser::~cmXMLParser()
25 this->CleanupParser();
29 int cmXMLParser::Parse(const char* string)
31 return this->InitializeParser() &&
32 this->ParseChunk(string, strlen(string)) && this->CleanupParser();
35 int cmXMLParser::ParseFile(const char* file)
41 cmsys::ifstream ifs(file);
46 std::ostringstream str;
48 return this->Parse(str.str().c_str());
51 int cmXMLParser::InitializeParser()
54 std::cerr << "Parser already initialized" << std::endl;
59 // Create the expat XML parser.
60 this->Parser = XML_ParserCreate(nullptr);
61 XML_SetElementHandler(static_cast<XML_Parser>(this->Parser),
62 &cmXMLParserStartElement, &cmXMLParserEndElement);
63 XML_SetCharacterDataHandler(static_cast<XML_Parser>(this->Parser),
64 &cmXMLParserCharacterDataHandler);
65 XML_SetUserData(static_cast<XML_Parser>(this->Parser), this);
70 int cmXMLParser::ParseChunk(const char* inputString,
71 std::string::size_type length)
74 std::cerr << "Parser not initialized" << std::endl;
79 res = this->ParseBuffer(inputString, length);
86 int cmXMLParser::CleanupParser()
89 std::cerr << "Parser not initialized" << std::endl;
93 int result = !this->ParseError;
95 // Tell the expat XML parser about the end-of-input.
96 if (!XML_Parse(static_cast<XML_Parser>(this->Parser), "", 0, 1)) {
97 this->ReportXmlParseError();
102 // Clean up the parser.
103 XML_ParserFree(static_cast<XML_Parser>(this->Parser));
104 this->Parser = nullptr;
109 int cmXMLParser::ParseBuffer(const char* buffer, std::string::size_type count)
111 // Pass the buffer to the expat XML parser.
112 if (!XML_Parse(static_cast<XML_Parser>(this->Parser), buffer,
113 static_cast<int>(count), 0)) {
114 this->ReportXmlParseError();
120 int cmXMLParser::ParseBuffer(const char* buffer)
122 return this->ParseBuffer(buffer, static_cast<int>(strlen(buffer)));
125 int cmXMLParser::ParsingComplete()
127 // Default behavior is to parse to end of stream.
131 void cmXMLParser::StartElement(const std::string& name, const char** /*atts*/)
133 std::cout << "Start element: " << name << std::endl;
136 void cmXMLParser::EndElement(const std::string& name)
138 std::cout << "End element: " << name << std::endl;
141 void cmXMLParser::CharacterDataHandler(const char* /*inData*/,
146 int cmXMLParser::IsSpace(char c)
151 const char* cmXMLParser::FindAttribute(const char** atts,
152 const char* attribute)
154 if (atts && attribute) {
155 for (const char** a = atts; *a && *(a + 1); a += 2) {
156 if (strcmp(*a, attribute) == 0) {
164 void cmXMLParserStartElement(void* parser, const char* name, const char** atts)
166 // Begin element handler that is registered with the XML_Parser.
167 // This just casts the user data to a cmXMLParser and calls
169 static_cast<cmXMLParser*>(parser)->StartElement(name, atts);
172 void cmXMLParserEndElement(void* parser, const char* name)
174 // End element handler that is registered with the XML_Parser. This
175 // just casts the user data to a cmXMLParser and calls EndElement.
176 static_cast<cmXMLParser*>(parser)->EndElement(name);
179 void cmXMLParserCharacterDataHandler(void* parser, const char* data,
182 // Character data handler that is registered with the XML_Parser.
183 // This just casts the user data to a cmXMLParser and calls
184 // CharacterDataHandler.
185 static_cast<cmXMLParser*>(parser)->CharacterDataHandler(data, length);
188 void cmXMLParser::ReportXmlParseError()
190 XML_Parser parser = static_cast<XML_Parser>(this->Parser);
191 this->ReportError(static_cast<int>(XML_GetCurrentLineNumber(parser)),
192 static_cast<int>(XML_GetCurrentColumnNumber(parser)),
193 XML_ErrorString(XML_GetErrorCode(parser)));
196 void cmXMLParser::ReportError(int line, int /*unused*/, const char* msg)
198 if (this->ReportCallback) {
199 this->ReportCallback(line, msg, this->ReportCallbackData);
201 std::cerr << "Error parsing XML in stream at line " << line << ": " << msg